merge fx-team to m-c
authorRob Campbell <rcampbell@mozilla.com>
Sat, 21 Jan 2012 11:33:53 -0400
changeset 86273 d43360499b86d66d82ed0e585b75bb3237864ad2
parent 86272 1655a3f30b7e29337f6ef11987965bf0abf3aee7 (current diff)
parent 86264 bf4edffd939497bafb3ec96a7cd7e983966c0a39 (diff)
child 86274 8297a76e055272e728e6a5ceda034466ccfc26cc
child 86316 946022ef981f3c5dcd358a3c2e3df75d29aa6ccb
child 109197 6ba07330f431d6f08ea4bc8ad067e6fee2e4a979
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
merge fx-team to m-c
browser/app/profile/firefox.js
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_enter.js
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_exit.js
build/unix/build-toolchain/det-ar.sh
dom/interfaces/html/nsIDOMMozBrowserFrameElement.idl
dom/tests/mochitest/general/test_getContentState.html
--- a/accessible/src/base/Statistics.h
+++ b/accessible/src/base/Statistics.h
@@ -44,16 +44,19 @@
 
 namespace mozilla {
 namespace a11y {
 namespace statistics {
 
   inline void A11yInitialized()
     { Telemetry::Accumulate(Telemetry::A11Y_INSTANTIATED, true); }
 
+  inline void A11yConsumers(PRUint32 aConsumer)
+    { Telemetry::Accumulate(Telemetry::A11Y_CONSUMERS, aConsumer); }
+
   /**
    * Report that ISimpleDOM* has been used.
    */
   inline void ISimpleDOMUsed()
     { Telemetry::Accumulate(Telemetry::ISIMPLE_DOM_USAGE, 1); }
 
   /**
    * Report that IAccessibleTable has been used.
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -904,29 +904,18 @@ static bool HasRelatedContent(nsIContent
 {
   nsAutoString id;
   if (!aContent || !nsCoreUtils::GetID(aContent, id) || id.IsEmpty()) {
     return false;
   }
 
   // If the given ID is referred by relation attribute then create an accessible
   // for it. Take care of HTML elements only for now.
-  if (aContent->IsHTML() &&
-      nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id))
-    return true;
-
-  nsIContent *ancestorContent = aContent;
-  while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
-    if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
-        // ancestor has activedescendant property, this content could be active
-      return true;
-    }
-  }
-
-  return false;
+  return aContent->IsHTML() &&
+    nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id);
 }
 
 nsAccessible*
 nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
                                               nsIPresShell* aPresShell,
                                               nsIWeakReference* aWeakShell,
                                               bool* aIsSubtreeHidden)
 {
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2909,31 +2909,28 @@ nsAccessible::SetCurrentItem(nsAccessibl
     mContent->SetAttr(kNameSpaceID_None,
                       nsGkAtoms::aria_activedescendant, idStr, true);
   }
 }
 
 nsAccessible*
 nsAccessible::ContainerWidget() const
 {
-  nsIAtom* idAttribute = mContent->GetIDAttributeName();
-  if (idAttribute) {
-    if (mContent->HasAttr(kNameSpaceID_None, idAttribute)) {
-      for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
-        nsIContent* parentContent = parent->GetContent();
-        if (parentContent &&
-            parentContent->HasAttr(kNameSpaceID_None,
-                                   nsGkAtoms::aria_activedescendant)) {
-          return parent;
-        }
-
-        // Don't cross DOM document boundaries.
-        if (parent->IsDocumentNode())
-          break;
+  if (HasARIARole() && mContent->HasID()) {
+    for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
+      nsIContent* parentContent = parent->GetContent();
+      if (parentContent &&
+        parentContent->HasAttr(kNameSpaceID_None,
+                               nsGkAtoms::aria_activedescendant)) {
+        return parent;
       }
+
+      // Don't cross DOM document boundaries.
+      if (parent->IsDocumentNode())
+        break;
     }
   }
   return nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible protected methods
 
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -162,16 +162,24 @@ public:
   {
     if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
       return NativeRole();
 
     return ARIARoleInternal();
   }
 
   /**
+   * Return true if ARIA role is specified on the element.
+   */
+  inline bool HasARIARole() const
+  {
+    return mRoleMapEntry;
+  }
+
+  /**
    * Return accessible role specified by ARIA (see constants in
    * roles).
    */
   inline mozilla::a11y::role ARIARole()
   {
     if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
       return mozilla::a11y::roles::NOTHING;
 
--- a/accessible/src/msaa/Compatibility.cpp
+++ b/accessible/src/msaa/Compatibility.cpp
@@ -35,16 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Compatibility.h"
 
 #include "nsWinUtils.h"
+#include "Statistics.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 /**
  * Return true if module version is lesser than the given version.
@@ -79,28 +80,47 @@ IsModuleVersionLessThan(HMODULE aModuleH
 // Compatibility
 ////////////////////////////////////////////////////////////////////////////////
 
 PRUint32 Compatibility::sMode = Compatibility::NoCompatibilityMode;
 
 void
 Compatibility::Init()
 {
+  // Note we collect some AT statistics/telemetry here for convenience.
+
   HMODULE jawsHandle = ::GetModuleHandleW(L"jhook");
   if (jawsHandle) {
     sMode |= JAWSMode;
     // IA2 off mode for JAWS versions below 8.0.2173.
-    if (IsModuleVersionLessThan(jawsHandle, 8, 2173))
+    if (IsModuleVersionLessThan(jawsHandle, 8, 2173)) {
       sMode |= IA2OffMode;
+      statistics::A11yConsumers(OLDJAWS);
+    } else {
+      statistics::A11yConsumers(JAWS);
+    }
   }
 
-  if (::GetModuleHandleW(L"gwm32inc"))
+  if (::GetModuleHandleW(L"gwm32inc")) {
     sMode |= WEMode;
-  if (::GetModuleHandleW(L"dolwinhk"))
+    statistics::A11yConsumers(WE);
+  }
+  if (::GetModuleHandleW(L"dolwinhk")) {
     sMode |= DolphinMode;
+    statistics::A11yConsumers(DOLPHIN);
+  }
+
+  if (::GetModuleHandleW(L"STSA32"))
+    statistics::A11yConsumers(SEROTEK);
+
+  if (::GetModuleHandleW(L"nvdaHelperRemote"))
+    statistics::A11yConsumers(NVDA);
+
+  if (::GetModuleHandleW(L"OsmHooks"))
+    statistics::A11yConsumers(COBRA);
 
   // Turn off new tab switching for Jaws and WE.
   if (sMode & JAWSMode || sMode & WEMode) {
     // Check to see if the pref for disallowing CtrlTab is already set. If so,
     // bail out (respect the user settings). If not, set it.
     if (!Preferences::HasUserValue("browser.ctrlTab.disallowForScreenReaders"))
       Preferences::SetBool("browser.ctrlTab.disallowForScreenReaders", true);
   }
--- a/accessible/src/msaa/Compatibility.h
+++ b/accessible/src/msaa/Compatibility.h
@@ -92,16 +92,29 @@ private:
   enum {
     NoCompatibilityMode = 0,
     JAWSMode = 1 << 0,
     WEMode = 1 << 1,
     DolphinMode = 1 << 2,
     IA2OffMode = 1 << 3
   };
 
+  /**
+   * List of detected consumers of a11y (used for statistics/telemetry)
+   */
+  enum {
+    NVDA = 0,
+    JAWS = 1,
+    OLDJAWS = 2,
+    WE = 3,
+    DOLPHIN = 4,
+    SEROTEK = 5,
+    COBRA = 6
+  };
+
 private:
   static PRUint32 sMode;
 };
 
 } // a11y namespace
 } // mozilla namespace
 
 #endif
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -389,16 +389,20 @@ pref("security.fileuri.strict_origin_pol
 // deep within the bowels of the widgetry system.  Remove me when GL
 // compositing isn't default disabled in widget/android.
 pref("layers.acceleration.force-enabled", true);
 
 // screen.enabled and screen.brightness properties.
 pref("dom.screenEnabledProperty.enabled", true);
 pref("dom.screenBrightnessProperty.enabled", true);
 
+// Enable browser frame
+pref("dom.mozBrowserFramesEnabled", true);
+pref("dom.mozBrowserFramesWhitelist", "http://localhost:6666");
+
 // Temporary permission hack for WebSMS
 pref("dom.sms.enabled", true);
 pref("dom.sms.whitelist", "file://,http://localhost:6666");
 // Ignore X-Frame-Options headers.
 pref("b2g.ignoreXFrameOptions", true);
 
 // "Preview" landing of bug 710563, which is bogged down in analysis
 // of talos regression.  This is a needed change for higher-framerate
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -78,16 +78,20 @@ LOCAL_INCLUDES += -I$(DEPTH)/build
 DEFINES += -DXPCOM_GLUE
 STL_FLAGS=
 
 LIBS += \
 	$(EXTRA_DSO_LIBS) \
 	$(XPCOM_STANDALONE_GLUE_LDOPTS) \
 	$(NULL)
 
+ifdef MOZ_LINKER
+LIBS += $(ZLIB_LIBS)
+endif
+
 ifndef MOZ_WINCONSOLE
 ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
 
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1325894427000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1327073984000">
   <emItems>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}">
                         <versionRange  minVersion=" " severity="1">
                     </versionRange>
@@ -34,16 +34,20 @@
       <emItem  blockID="i39" id="{c2d64ff7-0ab8-4263-89c9-ea3b0f8f050c}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i42" id="{D19CA586-DD6C-4a0a-96F8-14644F340D60}">
                         <versionRange  minVersion="0.1" maxVersion="14.4.0" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i53" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
+                        <versionRange  minVersion="2.0.3" maxVersion="2.0.3">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i10" id="{8CE11043-9A15-4207-A565-0C94C42D590D}">
                         </emItem>
       <emItem  blockID="i1" id="mozilla_cc@internetdownloadmanager.com">
                         <versionRange  minVersion="2.1" maxVersion="3.3">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
@@ -61,20 +65,31 @@
                         </emItem>
       <emItem  blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
                         <versionRange  minVersion="1.2" maxVersion="1.2">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i50" id="firebug@software.joehewitt.com">
+                        <versionRange  minVersion="0" maxVersion="0">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="9.0a1" maxVersion="9.*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i51" id="admin@youtubeplayer.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
                         <versionRange  minVersion="0.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="9.0a1" maxVersion="9.0" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i23" id="firefox@bandoo.com">
@@ -134,20 +149,22 @@
                               <versionRange  minVersion="8.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i3" id="langpack-vi-VN@firefox.mozilla.org">
                         <versionRange  minVersion="2.0" maxVersion="2.0">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i49" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE63}">
-                        </emItem>
       <emItem  blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
                         </emItem>
+      <emItem  blockID="i52" id="ff-ext@youtube">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
                         <versionRange  minVersion="0.1" maxVersion="1.3.328.4" severity="1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1pre" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i15" id="personas@christopher.beard">
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -799,16 +799,20 @@ pref("browser.sessionstore.max_resumed_c
 // restore_on_demand overrides MAX_CONCURRENT_TAB_RESTORES (sessionstore constant)
 // and restore_hidden_tabs. When true, tabs will not be restored until they are
 // focused (also applies to tabs that aren't visible). When false, the values
 // for MAX_CONCURRENT_TAB_RESTORES and restore_hidden_tabs are respected.
 // Selected tabs are always restored regardless of this pref.
 pref("browser.sessionstore.restore_on_demand", false);
 // Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not
 pref("browser.sessionstore.restore_hidden_tabs", false);
+// If restore_on_demand is set, pinned tabs are restored on startup by default.
+// When set to true, this pref overrides that behavior, and pinned tabs will only
+// be restored when they are focused.
+pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
 
 // allow META refresh by default
 pref("accessibility.blockautorefresh", false);
 
 // Whether history is enabled or not.
 pref("places.history.enabled", true);
 
 // the (maximum) number of the recent visits to sample
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -227,18 +227,18 @@ var FullZoom = {
     // Avoid the cps roundtrip and apply the default/global pref.
     if (aURI.spec == "about:blank") {
       this._applyPrefToSetting(undefined, aBrowser);
       return;
     }
 
     let browser = aBrowser || gBrowser.selectedBrowser;
 
-    // Image documents should always start at 1, and are not affected by prefs.
-    if (!aIsTabSwitch && browser.contentDocument instanceof ImageDocument) {
+    // 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);
       this._applyPrefToSetting(zoomValue, browser);
     } else {
@@ -304,40 +304,40 @@ var FullZoom = {
    * one.
    **/
   _applyPrefToSetting: function FullZoom__applyPrefToSetting(aValue, aBrowser) {
     if ((!this.siteSpecific) || gInPrintPreviewMode)
       return;
 
     var browser = aBrowser || (gBrowser && gBrowser.selectedBrowser);
     try {
-      if (browser.contentDocument instanceof ImageDocument)
+      if (browser.contentDocument.mozSyntheticDocument)
         return;
 
       if (typeof aValue != "undefined")
         ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue));
       else if (typeof this.globalValue != "undefined")
         ZoomManager.setZoomForBrowser(browser, this.globalValue);
       else
         ZoomManager.setZoomForBrowser(browser, 1);
     }
     catch(ex) {}
   },
 
   _applySettingToPref: function FullZoom__applySettingToPref() {
     if (!this.siteSpecific || gInPrintPreviewMode ||
-        content.document instanceof ImageDocument)
+        content.document.mozSyntheticDocument)
       return;
 
     var zoomLevel = ZoomManager.zoom;
     Services.contentPrefs.setPref(gBrowser.currentURI, this.name, zoomLevel);
   },
 
   _removePref: function FullZoom__removePref() {
-    if (!(content.document instanceof ImageDocument))
+    if (!(content.document.mozSyntheticDocument))
       Services.contentPrefs.removePref(gBrowser.currentURI, this.name);
   },
 
 
   //**************************************************************************//
   // Utilities
 
   _ensureValid: function FullZoom__ensureValid(aValue) {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3035,17 +3035,17 @@ function getMarkupDocumentViewer()
  *       (pinkerton)
  **/
 function FillInHTMLTooltip(tipElement)
 {
   var retVal = false;
   // Don't show the tooltip if the tooltip node is a XUL element, a document or is disconnected.
   if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" ||
       !tipElement.ownerDocument ||
-      tipElement.ownerDocument.compareDocumentPosition(tipElement) == document.DOCUMENT_POSITION_DISCONNECTED)
+      (tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED))
     return retVal;
 
   const XLinkNS = "http://www.w3.org/1999/xlink";
 
 
   var titleText = null;
   var XLinkTitleText = null;
   var SVGTitleText = null;
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -169,16 +169,17 @@ endif
                  browser_bug616836.js \
                  browser_bug623155.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_bug664672.js \
                  browser_bug710878.js \
+                 browser_bug719271.js \
                  browser_canonizeURL.js \
                  browser_findbarClose.js \
                  browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
                  browser_disablechrome.js \
                  browser_discovery.js \
@@ -226,16 +227,17 @@ endif
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
                  bug592338.html \
                  disablechrome.html \
                  discovery.html \
                  domplate_test.js \
                  moz.png \
+                 video.ogg \
                  test_bug435035.html \
                  test_bug462673.html \
                  page_style_sample.html \
                  feed_tab.html \
                  plugin_unknown.html \
                  plugin_test.html \
                  plugin_both.html \
                  plugin_both2.html \
--- a/browser/base/content/test/browser_bug416661.js
+++ b/browser/base/content/test/browser_bug416661.js
@@ -38,17 +38,18 @@ function test() {
   gBrowser.selectedTab = tabElm;
 
   afterZoomAndLoad(start_test_prefNotSet);
   content.location = 
     "http://mochi.test:8888/browser/browser/base/content/test/zoom_test.html";
 }
 
 function afterZoomAndLoad(cb) {
-  let didLoad = didZoom = false;
+  let didLoad = false;
+  let didZoom = false;
   tabElm.linkedBrowser.addEventListener("load", function() {
     tabElm.linkedBrowser.removeEventListener("load", arguments.callee, true);
     didLoad = true;
     if (didZoom)
       executeSoon(cb);
   }, true);
   let oldSZFB = ZoomManager.setZoomForBrowser;
   ZoomManager.setZoomForBrowser = function(browser, value) {
--- a/browser/base/content/test/browser_bug555224.js
+++ b/browser/base/content/test/browser_bug555224.js
@@ -32,17 +32,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 const TEST_PAGE = "/browser/browser/base/content/test/dummy_page.html";
 var gTestTab, gBgTab, gTestZoom;
 
 function afterZoomAndLoad(aCallback, aTab) {
-  let didLoad = didZoom = false;
+  let didLoad = false;
+  let didZoom = false;
   aTab.linkedBrowser.addEventListener("load", function() {
     aTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
     didLoad = true;
     if (didZoom)
       executeSoon(aCallback);
   }, true);
   let oldAPTS = FullZoom._applyPrefToSetting;
   FullZoom._applyPrefToSetting = function(value, browser) {
--- a/browser/base/content/test/browser_bug592338.js
+++ b/browser/base/content/test/browser_bug592338.js
@@ -1,15 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
 
-Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm");
+var tempScope = {};
+Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", tempScope);
+var LightweightThemeManager = tempScope.LightweightThemeManager;
 
 function wait_for_notification(aCallback) {
   PopupNotifications.panel.addEventListener("popupshown", function() {
     PopupNotifications.panel.removeEventListener("popupshown", arguments.callee, false);
     aCallback(PopupNotifications.panel);
   }, false);
 }
 
--- a/browser/base/content/test/browser_bug623155.js
+++ b/browser/base/content/test/browser_bug623155.js
@@ -38,16 +38,18 @@ 6. The redirected URI is <https://www.ba
    a cert-error page.
 
 7. Check the URLbar's value, expecting <https://www.bank1.com/#FG>
 
 8. End.
 
  */
 
+var gNewTab;
+
 function test() {
   waitForExplicitFinish();
 
   // Load a URI in the background.
   gNewTab = gBrowser.addTab(REDIRECT_FROM + "#BG");
   gBrowser.getBrowserForTab(gNewTab)
           .webProgress
           .addProgressListener(gWebProgressListener,
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug719271.js
@@ -0,0 +1,141 @@
+/* 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/. */
+"use strict";
+
+const TEST_PAGE = "http://example.org/browser/browser/base/content/test/zoom_test.html";
+const TEST_VIDEO = "http://example.org/browser/browser/base/content/test/video.ogg";
+
+var gTab1, gTab2, gLevel1, gLevel2;
+
+function test() {
+  waitForExplicitFinish();
+
+  gTab1 = gBrowser.addTab();
+  gTab2 = gBrowser.addTab();
+  gBrowser.selectedTab = gTab1;
+
+  load(gTab1, TEST_PAGE, function() {
+    load(gTab2, TEST_VIDEO, zoomTab1);
+  });
+}
+
+function zoomTab1() {
+  is(gBrowser.selectedTab, gTab1, "Tab 1 is selected");
+  zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1");
+  zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1");
+
+  FullZoom.enlarge();
+  gLevel1 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1));
+
+  ok(gLevel1 > 1, "New zoom for tab 1 should be greater than 1");
+  zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2");
+
+  gBrowser.selectedTab = gTab2;
+  zoomTest(gTab2, 1, "Tab 2 is still unzoomed after it is selected");
+  zoomTest(gTab1, gLevel1, "Tab 1 is still zoomed");
+
+  zoomTab2();
+}
+
+function zoomTab2() {
+  is(gBrowser.selectedTab, gTab2, "Tab 2 is selected");
+
+  FullZoom.reduce();
+  let gLevel2 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab2));
+
+  ok(gLevel2 < 1, "New zoom for tab 2 should be less than 1");
+  zoomTest(gTab1, gLevel1, "Zooming tab 2 should not affect tab 1");
+
+  afterZoom(function() {
+    zoomTest(gTab1, gLevel1, "Tab 1 should have the same zoom after it's selected");
+
+    testNavigation();
+  });
+  gBrowser.selectedTab = gTab1;
+}
+
+function testNavigation() {
+  load(gTab1, TEST_VIDEO, function() {
+    zoomTest(gTab1, 1, "Zoom should be 1 when a video was loaded");
+    navigate(BACK, function() {
+      zoomTest(gTab1, gLevel1, "Zoom should be restored when a page is loaded");
+      navigate(FORWARD, function() {
+        zoomTest(gTab1, 1, "Zoom should be 1 again when navigating back to a video");
+        finishTest();
+      });
+    });
+  });
+}
+
+var finishTestStarted  = false;
+function finishTest() {
+  ok(!finishTestStarted, "finishTest called more than once");
+  finishTestStarted = true;
+
+  gBrowser.selectedTab = gTab1;
+  FullZoom.reset();
+  gBrowser.removeTab(gTab1);
+
+  gBrowser.selectedTab = gTab2;
+  FullZoom.reset();
+  gBrowser.removeTab(gTab2);
+
+  finish();
+}
+
+function zoomTest(tab, val, msg) {
+  is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg);
+}
+
+function load(tab, url, cb) {
+  let didLoad = false;
+  let didZoom = false;
+  tab.linkedBrowser.addEventListener("load", function onload(event) {
+    event.currentTarget.removeEventListener("load", onload, true);
+    didLoad = true;
+    if (didZoom)
+      executeSoon(cb);
+  }, true);
+
+  afterZoom(function() {
+    didZoom = true;
+    if (didLoad)
+      executeSoon(cb);
+  });
+
+  tab.linkedBrowser.loadURI(url);
+}
+
+const BACK = 0;
+const FORWARD = 1;
+function navigate(direction, cb) {
+  let didPs = false;
+  let didZoom = false;
+  gBrowser.addEventListener("pageshow", function onpageshow(event) {
+    gBrowser.removeEventListener("pageshow", onpageshow, true);
+    didPs = true;
+    if (didZoom)
+      executeSoon(cb);
+  }, true);
+
+  afterZoom(function() {
+    didZoom = true;
+    if (didPs)
+      executeSoon(cb);
+  });
+
+  if (direction == BACK)
+    gBrowser.goBack();
+  else if (direction == FORWARD)
+    gBrowser.goForward();
+}
+
+function afterZoom(cb) {
+  let oldSZFB = ZoomManager.setZoomForBrowser;
+  ZoomManager.setZoomForBrowser = function(browser, value) {
+    oldSZFB.call(ZoomManager, browser, value);
+    ZoomManager.setZoomForBrowser = oldSZFB;
+    executeSoon(cb);
+  };
+}
--- a/browser/base/content/test/browser_gestureSupport.js
+++ b/browser/base/content/test/browser_gestureSupport.js
@@ -378,17 +378,17 @@ function test_latchedGesture(gesture, in
   };
 
   // Test the gestures in each direction.
   test_emitLatchedEvents(eventPrefix, 500, cmd);
   test_emitLatchedEvents(eventPrefix, -500, cmd);
 
   // Restore the gesture to its original configuration.
   gPrefService.setBoolPref(branch + "latched", oldLatchedValue);
-  for (dir in cmd)
+  for (let dir in cmd)
     test_removeCommand(cmd[dir]);
 }
 
 // Test whether non-latched events are triggered upon sufficient motion.
 function test_thresholdGesture(gesture, inc, dec, eventPrefix)
 {
   let branch = test_prefBranch + gesture + ".";
 
--- a/browser/base/content/test/browser_identity_UI.js
+++ b/browser/base/content/test/browser_identity_UI.js
@@ -63,17 +63,17 @@ var tests = [
   {
     name: "IP address",
     location: "http://127.0.0.1:8888/",
     host: "127.0.0.1:8888",
     effectiveHost: "127.0.0.1"
   },
 ]
 
-let gCurrentTest, gCurrentTestIndex = -1;
+let gCurrentTest, gCurrentTestIndex = -1, gTestDesc;
 // Go through the tests in both directions, to add additional coverage for
 // transitions between different states.
 let gForward = true;
 function nextTest() {
   if (gForward)
     gCurrentTestIndex++;
   else
     gCurrentTestIndex--;
--- a/browser/components/privatebrowsing/test/browser/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -51,16 +51,19 @@ include $(topsrcdir)/config/rules.mk
 		browser_privatebrowsing_commandline_toggle.js \
 		browser_privatebrowsing_crh.js \
 		browser_privatebrowsing_fastswitch.js \
 		browser_privatebrowsing_findbar.js \
 		browser_privatebrowsing_forgetthissite.js \
 		browser_privatebrowsing_geoprompt.js \
 		browser_privatebrowsing_geoprompt_page.html \
 		browser_privatebrowsing_import.js \
+		browser_privatebrowsing_localStorage.js \
+		browser_privatebrowsing_localStorage_page1.html \
+		browser_privatebrowsing_localStorage_page2.html \
 		browser_privatebrowsing_newwindow_stopcmd.js \
 		browser_privatebrowsing_opendir.js \
 		browser_privatebrowsing_openlocation.js \
 		browser_privatebrowsing_pageinfo.js \
 		browser_privatebrowsing_placestitle.js \
 		browser_privatebrowsing_popupblocker.js \
 		browser_privatebrowsing_popupmode.js \
 		browser_privatebrowsing_protocolhandler.js \
@@ -87,16 +90,15 @@ include $(topsrcdir)/config/rules.mk
 		$(NULL)
 
 # Disabled until bug 564934 is fixed:
 #		browser_privatebrowsing_downloadmonitor.js \
 
 # Turn off private browsing tests that perma-timeout on Linux.
 ifneq (Linux,$(OS_ARCH))
 _BROWSER_TEST_FILES += \
-		browser_privatebrowsing_beforeunload_enter.js \
-		browser_privatebrowsing_beforeunload_exit.js \
+		browser_privatebrowsing_beforeunload.js \
 		browser_privatebrowsing_cookieacceptdialog.js \
 		$(NULL)
 endif
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload.js
@@ -0,0 +1,166 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Nochum Sossonko.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Nochum Sossonko <highmind63@gmail.com> (Original Author)
+ *   Ehsan Akhgari <ehsan@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This test makes sure that cancelling the unloading of a page with a beforeunload
+// handler prevents the private browsing mode transition.
+
+function test() {
+  const TEST_PAGE_1 = "data:text/html,<body%20onbeforeunload='return%20false;'>first</body>";
+  const TEST_PAGE_2 = "data:text/html,<body%20onbeforeunload='return%20false;'>second</body>";
+  let pb = Cc["@mozilla.org/privatebrowsing;1"]
+             .getService(Ci.nsIPrivateBrowsingService);
+
+  let rejectDialog = 0;
+  let acceptDialog = 0;
+  let confirmCalls = 0;
+  function promptObserver(aSubject, aTopic, aData) {
+    let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
+    confirmCalls++;
+    if (acceptDialog-- > 0)
+      dialogWin.document.documentElement.getButton("accept").click();
+    else if (rejectDialog-- > 0)
+      dialogWin.document.documentElement.getButton("cancel").click();
+  }
+
+  Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
+
+  waitForExplicitFinish();
+  let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
+  browser1.addEventListener("load", function() {
+    browser1.removeEventListener("load", arguments.callee, true);
+
+    let browser2 = gBrowser.getBrowserForTab(gBrowser.addTab());
+    browser2.addEventListener("load", function() {
+      browser2.removeEventListener("load", arguments.callee, true);
+
+      rejectDialog = 1;
+      pb.privateBrowsingEnabled = true;
+
+      ok(!pb.privateBrowsingEnabled, "Private browsing mode should not have been activated");
+      is(confirmCalls, 1, "Only one confirm box should be shown");
+      is(gBrowser.tabs.length, 3,
+         "No tabs should be closed because private browsing mode transition was canceled");
+      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
+         "The first tab should be a blank tab");
+      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
+         "The middle tab should be the same one we opened");
+      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+         "The last tab should be the same one we opened");
+      is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
+
+      confirmCalls = 0;
+      acceptDialog = 2;
+      pb.privateBrowsingEnabled = true;
+
+      ok(pb.privateBrowsingEnabled, "Private browsing mode should have been activated");
+      is(confirmCalls, 2, "Only two confirm boxes should be shown");
+      is(gBrowser.tabs.length, 1,
+         "Incorrect number of tabs after transition into private browsing");
+      gBrowser.selectedBrowser.addEventListener("load", function() {
+        gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+        is(gBrowser.currentURI.spec, "about:privatebrowsing",
+           "Incorrect page displayed after private browsing transition");
+        is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
+
+        gBrowser.selectedBrowser.addEventListener("load", function() {
+          gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+          gBrowser.selectedTab = gBrowser.addTab();
+          gBrowser.selectedBrowser.addEventListener("load", function() {
+            gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+            confirmCalls = 0;
+            rejectDialog = 1;
+            pb.privateBrowsingEnabled = false;
+
+            ok(pb.privateBrowsingEnabled, "Private browsing mode should not have been deactivated");
+            is(confirmCalls, 1, "Only one confirm box should be shown");
+            is(gBrowser.tabs.length, 2,
+               "No tabs should be closed because private browsing mode transition was canceled");
+            is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, TEST_PAGE_1,
+               "The first tab should be the same one we opened");
+            is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+               "The last tab should be the same one we opened");
+            is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
+
+            confirmCalls = 0;
+            acceptDialog = 2;
+            pb.privateBrowsingEnabled = false;
+
+            ok(!pb.privateBrowsingEnabled, "Private browsing mode should have been deactivated");
+            is(confirmCalls, 2, "Only two confirm boxes should be shown");
+            is(gBrowser.tabs.length, 3,
+               "Incorrect number of tabs after transition into private browsing");
+
+            let loads = 0;
+            function waitForLoad(event) {
+              gBrowser.removeEventListener("load", arguments.callee, true);
+
+              if (++loads != 3)
+                return;
+
+              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
+                 "The first tab should be a blank tab");
+              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
+                 "The middle tab should be the same one we opened");
+              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+                 "The last tab should be the same one we opened");
+              is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
+              is(acceptDialog, 0, "Two prompts should have been raised");
+
+              acceptDialog = 2;
+              gBrowser.removeTab(gBrowser.tabContainer.lastChild);
+              gBrowser.removeTab(gBrowser.tabContainer.lastChild);
+              gBrowser.getBrowserAtIndex(gBrowser.tabContainer.selectedIndex).contentWindow.focus();
+
+              Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
+              finish();
+            }
+            for (let i = 0; i < gBrowser.browsers.length; ++i)
+              gBrowser.browsers[i].addEventListener("load", waitForLoad, true);
+          }, true);
+          gBrowser.selectedBrowser.loadURI(TEST_PAGE_2);
+        }, true);
+        gBrowser.selectedBrowser.loadURI(TEST_PAGE_1);
+      }, true);
+    }, true);
+    browser2.loadURI(TEST_PAGE_2);
+  }, true);
+  browser1.loadURI(TEST_PAGE_1);
+}
deleted file mode 100644
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_enter.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Private Browsing Tests.
- *
- * The Initial Developer of the Original Code is
- * Nochum Sossonko.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Nochum Sossonko <highmind63@gmail.com> (Original Author)
- *   Ehsan Akhgari <ehsan@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-// This test makes sure that cancelling the unloading of a page with a beforeunload
-// handler prevents the private browsing mode transition.
-
-function test() {
-  const TEST_PAGE_1 = "data:text/html,<body%20onbeforeunload='return%20false;'>first</body>";
-  const TEST_PAGE_2 = "data:text/html,<body%20onbeforeunload='return%20false;'>second</body>";
-  let pb = Cc["@mozilla.org/privatebrowsing;1"]
-             .getService(Ci.nsIPrivateBrowsingService);
-
-  let rejectDialog = 0;
-  let acceptDialog = 0;
-  let confirmCalls = 0;
-  function promptObserver(aSubject, aTopic, aData) {
-    let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
-    confirmCalls++;
-    if (acceptDialog-- > 0)
-      dialogWin.document.documentElement.getButton("accept").click();
-    else if (rejectDialog-- > 0)
-      dialogWin.document.documentElement.getButton("cancel").click();
-  }
-
-  Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
-
-  waitForExplicitFinish();
-  let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
-  browser1.addEventListener("load", function() {
-    browser1.removeEventListener("load", arguments.callee, true);
-
-    let browser2 = gBrowser.getBrowserForTab(gBrowser.addTab());
-    browser2.addEventListener("load", function() {
-      browser2.removeEventListener("load", arguments.callee, true);
-
-      rejectDialog = 1;
-      pb.privateBrowsingEnabled = true;
-
-      ok(!pb.privateBrowsingEnabled, "Private browsing mode should not have been activated");
-      is(confirmCalls, 1, "Only one confirm box should be shown");
-      is(gBrowser.tabs.length, 3,
-         "No tabs should be closed because private browsing mode transition was canceled");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
-         "The first tab should be a blank tab");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
-         "The middle tab should be the same one we opened");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
-         "The last tab should be the same one we opened");
-      is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
-
-      confirmCalls = 0;
-      acceptDialog = 2;
-      pb.privateBrowsingEnabled = true;
-
-      ok(pb.privateBrowsingEnabled, "Private browsing mode should have been activated");
-      is(confirmCalls, 2, "Only two confirm boxes should be shown");
-      is(gBrowser.tabs.length, 1,
-         "Incorrect number of tabs after transition into private browsing");
-      gBrowser.selectedBrowser.addEventListener("load", function() {
-        gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-        is(gBrowser.currentURI.spec, "about:privatebrowsing",
-           "Incorrect page displayed after private browsing transition");
-        is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
-
-        gBrowser.addTab();
-        gBrowser.removeTab(gBrowser.selectedTab);
-        Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-        pb.privateBrowsingEnabled = false;
-        Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
-        Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
-        gBrowser.getBrowserAtIndex(gBrowser.tabContainer.selectedIndex).contentWindow.focus();
-        finish();
-      }, true);
-    }, true);
-    browser2.loadURI(TEST_PAGE_2);
-  }, true);
-  browser1.loadURI(TEST_PAGE_1);
-}
deleted file mode 100644
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_exit.js
+++ /dev/null
@@ -1,125 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Private Browsing Tests.
- *
- * The Initial Developer of the Original Code is
- * Nochum Sossonko.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Nochum Sossonko <highmind63@gmail.com> (Original Author)
- *   Ehsan Akhgari <ehsan@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-// This test makes sure that cancelling the unloading of a page with a beforeunload
-// handler prevents the private browsing mode transition.
-
-function test() {
-  const TEST_PAGE_1 = "data:text/html,<body%20onbeforeunload='return%20false;'>first</body>";
-  const TEST_PAGE_2 = "data:text/html,<body%20onbeforeunload='return%20false;'>second</body>";
-  let pb = Cc["@mozilla.org/privatebrowsing;1"]
-             .getService(Ci.nsIPrivateBrowsingService);
-
-  let rejectDialog = 0;
-  let acceptDialog = 0;
-  let confirmCalls = 0;
-  function promptObserver(aSubject, aTopic, aData) {
-    let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
-    confirmCalls++;
-    if (acceptDialog-- > 0)
-      dialogWin.document.documentElement.getButton("accept").click();
-    else if (rejectDialog-- > 0)
-      dialogWin.document.documentElement.getButton("cancel").click();
-  }
-
-  Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
-  pb.privateBrowsingEnabled = true;
-
-  waitForExplicitFinish();
-  let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
-  browser1.addEventListener("load", function() {
-    browser1.removeEventListener("load", arguments.callee, true);
-
-    let browser2 = gBrowser.getBrowserForTab(gBrowser.addTab());
-    browser2.addEventListener("load", function() {
-      browser2.removeEventListener("load", arguments.callee, true);
-
-      confirmCalls = 0;
-      rejectDialog = 1;
-      pb.privateBrowsingEnabled = false;
-
-      ok(pb.privateBrowsingEnabled, "Private browsing mode should not have been deactivated");
-      is(confirmCalls, 1, "Only one confirm box should be shown");
-      is(gBrowser.tabs.length, 3,
-         "No tabs should be closed because private browsing mode transition was canceled");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:privatebrowsing",
-         "The first tab should be the same one we opened");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
-         "The last tab should be the same one we opened");
-      is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
-
-      confirmCalls = 0;
-      acceptDialog = 2;
-      pb.privateBrowsingEnabled = false;
-
-      ok(!pb.privateBrowsingEnabled, "Private browsing mode should have been deactivated");
-      is(confirmCalls, 2, "Only two confirm boxes should be shown");
-      is(gBrowser.tabs.length, 3,
-         "Incorrect number of tabs after transition into private browsing");
-
-      let loads = 0;
-      function waitForLoad(event) {
-        gBrowser.removeEventListener("load", arguments.callee, true);
-
-        if (++loads != 3)
-          return;
-
-        is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
-           "The first tab should be a blank tab");
-        is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
-           "The middle tab should be the same one we opened");
-        is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
-           "The last tab should be the same one we opened");
-        is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
-        is(acceptDialog, 0, "Two prompts should have been raised");
-
-        acceptDialog = 2;
-        gBrowser.removeTab(gBrowser.tabContainer.lastChild);
-        gBrowser.removeTab(gBrowser.tabContainer.lastChild);
-        gBrowser.getBrowserAtIndex(gBrowser.tabContainer.selectedIndex).contentWindow.focus();
-
-        Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
-        finish();
-      }
-      for (let i = 0; i < gBrowser.browsers.length; ++i)
-        gBrowser.browsers[i].addEventListener("load", waitForLoad, true);
-    }, true);
-    browser2.loadURI(TEST_PAGE_2);
-  }, true);
-  browser1.loadURI(TEST_PAGE_1);
-}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js
@@ -0,0 +1,59 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function test() {
+  let pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  waitForExplicitFinish();
+  pb.privateBrowsingEnabled = true;
+  let tab = gBrowser.selectedTab = gBrowser.addTab();
+  let browser = gBrowser.selectedBrowser;
+  browser.addEventListener('load', function() {
+    browser.removeEventListener('load', arguments.callee, true);
+    let tab2 = gBrowser.selectedTab = gBrowser.addTab();
+    browser.contentWindow.location = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' +
+                     'browser_privatebrowsing_localStorage_page2.html';
+    browser.addEventListener('load', function() {
+      browser.removeEventListener('load', arguments.callee, true);
+      is(browser.contentWindow.document.title, '2', "localStorage should contain 2 items");
+      pb.privateBrowsingEnabled = false;
+      finish();
+    }, true);
+  }, true);
+  browser.loadURI('http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' +
+                  'browser_privatebrowsing_localStorage_page1.html');
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page1.html
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script type="text/javascript">
+  localStorage.clear();
+  localStorage.setItem('test1', 'value1');
+</script>
+</head>
+<body>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page2.html
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script type="text/javascript">
+  localStorage.setItem('test2', 'value2');
+  document.title = localStorage.length;
+</script>
+</head>
+<body>
+</body>
+</html>
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -246,16 +246,19 @@ SessionStoreService.prototype = {
   _tabsToRestore: { priority: [], visible: [], hidden: [] },
   _tabsRestoringCount: 0,
 
   // overrides MAX_CONCURRENT_TAB_RESTORES and _restoreHiddenTabs when true
   _restoreOnDemand: false,
 
   // whether to restore hidden tabs or not, pref controlled.
   _restoreHiddenTabs: null,
+  
+  // whether to restore app tabs on demand or not, pref controlled.
+  _restorePinnedTabsOnDemand: null,
 
   // The state from the previous session (after restoring pinned tabs). This
   // state is persisted and passed through to the next session during an app
   // restart to make the third party add-on warning not trash the deferred
   // session
   _lastSessionState: null,
 
   // Whether we've been initialized
@@ -308,16 +311,20 @@ SessionStoreService.prototype = {
 
     this._restoreOnDemand =
       this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
     this._prefBranch.addObserver("sessionstore.restore_on_demand", this, true);
 
     this._restoreHiddenTabs =
       this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
     this._prefBranch.addObserver("sessionstore.restore_hidden_tabs", this, true);
+    
+    this._restorePinnedTabsOnDemand =
+      this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
+    this._prefBranch.addObserver("sessionstore.restore_pinned_tabs_on_demand", this, true);
 
     // Make sure gRestoreTabsProgressListener has a reference to sessionstore
     // so that it can make calls back in
     gRestoreTabsProgressListener.ss = this;
 
     // get file references
     this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
     this._sessionFileBackup = this._sessionFile.clone();
@@ -683,16 +690,20 @@ SessionStoreService.prototype = {
       case "sessionstore.restore_on_demand":
         this._restoreOnDemand =
           this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
         break;
       case "sessionstore.restore_hidden_tabs":
         this._restoreHiddenTabs =
           this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
         break;
+      case "sessionstore.restore_pinned_tabs_on_demand":
+        this._restorePinnedTabsOnDemand =
+          this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
+        break;
       }
       break;
     case "timer-callback": // timer call back for delayed saving
       this._saveTimer = null;
       this.saveState();
       break;
     case "private-browsing":
       switch (aData) {
@@ -3182,17 +3193,18 @@ SessionStoreService.prototype = {
    *   if we have already reached the limit for number of tabs to restore
    */
   restoreNextTab: function sss_restoreNextTab() {
     // If we call in here while quitting, we don't actually want to do anything
     if (this._loadState == STATE_QUITTING)
       return;
 
     // If it's not possible to restore anything, then just bail out.
-    if ((!this._tabsToRestore.priority.length && this._restoreOnDemand) ||
+    if ((this._restoreOnDemand &&
+        (this._restorePinnedTabsOnDemand || !this._tabsToRestore.priority.length)) ||
         this._tabsRestoringCount >= MAX_CONCURRENT_TAB_RESTORES)
       return;
 
     // Look in priority, then visible, then hidden
     let nextTabArray;
     if (this._tabsToRestore.priority.length) {
       nextTabArray = this._tabsToRestore.priority
     }
--- a/browser/components/sessionstore/test/browser_586068-cascaded_restore.js
+++ b/browser/components/sessionstore/test/browser_586068-cascaded_restore.js
@@ -51,21 +51,23 @@ function test() {
 
 // test_reloadCascade, test_reloadReload are generated tests that are run out
 // of cycle (since they depend on current state). They're listed in [tests] here
 // so that it is obvious when they run in respect to the other tests.
 let tests = [test_cascade, test_select, test_multiWindowState,
              test_setWindowStateNoOverwrite, test_setWindowStateOverwrite,
              test_setBrowserStateInterrupted, test_reload,
              /* test_reloadReload, */ test_reloadCascadeSetup,
-             /* test_reloadCascade, */ test_apptabs_only];
+             /* test_reloadCascade, */ test_apptabs_only,
+             test_restore_apptabs_ondemand];
 function runNextTest() {
   // Reset the pref
   try {
     Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
+    Services.prefs.clearUserPref("browser.sessionstore.restore_pinned_tabs_on_demand");
   } catch (e) {}
 
   // set an empty state & run the next test, or finish
   if (tests.length) {
     // Enumerate windows and close everything but our primary window. We can't
     // use waitForFocus() because apparently it's buggy. See bug 599253.
     var windowsEnum = Services.wm.getEnumerator("navigator:browser");
     while (windowsEnum.hasMoreElements()) {
@@ -772,16 +774,79 @@ function test_apptabs_only() {
     runNextTest();
   }
 
   window.gBrowser.addTabsProgressListener(progressListener);
   ss.setBrowserState(JSON.stringify(state));
 }
 
 
+// This test ensures that app tabs are not restored when restore_pinned_tabs_on_demand is set
+function test_restore_apptabs_ondemand() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);
+  Services.prefs.setBoolPref("browser.sessionstore.restore_pinned_tabs_on_demand", true);
+
+  // We have our own progress listener for this test, which we'll attach before our state is set
+  let progressListener = {
+    onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
+      if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
+          aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+          aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
+          aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
+        test_restore_apptabs_ondemand_progressCallback(aBrowser);
+    }
+  }
+
+  let state = { windows: [{ tabs: [
+    { entries: [{ url: "http://example.org/#1" }], extData: { "uniq": r() }, pinned: true },
+    { entries: [{ url: "http://example.org/#2" }], extData: { "uniq": r() }, pinned: true },
+    { entries: [{ url: "http://example.org/#3" }], extData: { "uniq": r() }, pinned: true },
+    { entries: [{ url: "http://example.org/#4" }], extData: { "uniq": r() } },
+    { entries: [{ url: "http://example.org/#5" }], extData: { "uniq": r() } },
+    { entries: [{ url: "http://example.org/#6" }], extData: { "uniq": r() } },
+    { entries: [{ url: "http://example.org/#7" }], extData: { "uniq": r() } },
+  ], selected: 5 }] };
+
+  let loadCount = 0;
+  let nextTestTimer;
+  function test_restore_apptabs_ondemand_progressCallback(aBrowser) {
+    loadCount++;
+
+    // get the tab
+    let tab;
+    for (let i = 0; i < window.gBrowser.tabs.length; i++) {
+      if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
+        tab = window.gBrowser.tabs[i];
+    }
+
+    // Check that the load only comes from the selected tab.
+    ok(gBrowser.selectedTab == tab,
+       "test_restore_apptabs_ondemand: load came from selected tab");
+
+    // We should get only 1 load: the selected tab
+    if (loadCount == 1) {
+      nextTestTimer = setTimeout(nextTest, 1000);
+      return;
+    }
+    else if (loadCount > 1) {
+      clearTimeout(nextTestTimer);
+    }
+
+    function nextTest() {
+      window.gBrowser.removeTabsProgressListener(progressListener);
+      runNextTest();
+    }
+    nextTest();
+  }
+
+  window.gBrowser.addTabsProgressListener(progressListener);
+  ss.setBrowserState(JSON.stringify(state));
+}
+
+
 function countTabs() {
   let needsRestore = 0,
       isRestoring = 0,
       wasRestored = 0;
 
   let windowsEnum = Services.wm.getEnumerator("navigator:browser");
 
   while (windowsEnum.hasMoreElements()) {
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -184,17 +184,16 @@ typedef struct {
   char* keyName;
   char* valueName;
   char* valueData;
 } SETTING;
 
 #define APP_REG_NAME L"Firefox"
 #define CLS_HTML "FirefoxHTML"
 #define CLS_URL "FirefoxURL"
-#define CPL_DESKTOP L"Control Panel\\Desktop"
 #define VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
 #define VAL_FILE_ICON "%APPPATH%,1"
 #define DI "\\DefaultIcon"
 #define SOP "\\shell\\open\\command"
 
 #define MAKE_KEY_NAME1(PREFIX, MID) \
   PREFIX MID
 
@@ -612,54 +611,51 @@ nsWindowsShellService::SetDesktopBackgro
   rv = file->GetPath(path);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // write the bitmap to a file in the profile directory
   rv = WriteBitmap(file, container);
 
   // if the file was written successfully, set it as the system wallpaper
   if (NS_SUCCEEDED(rv)) {
-     bool result = false;
-     DWORD  dwDisp = 0;
-     HKEY   key;
-     // Try to create/open a subkey under HKCU.
-     DWORD res = ::RegCreateKeyExW(HKEY_CURRENT_USER, CPL_DESKTOP,
-                                   0, NULL, REG_OPTION_NON_VOLATILE,
-                                   KEY_WRITE, NULL, &key, &dwDisp);
-    if (REG_SUCCEEDED(res)) {
-      PRUnichar tile[2], style[2];
-      switch (aPosition) {
-        case BACKGROUND_TILE:
-          tile[0] = '1';
-          style[0] = '1';
-          break;
-        case BACKGROUND_CENTER:
-          tile[0] = '0';
-          style[0] = '0';
-          break;
-        case BACKGROUND_STRETCH:
-          tile[0] = '0';
-          style[0] = '2';
-          break;
-      }
-      tile[1] = '\0';
-      style[1] = '\0';
+    nsCOMPtr<nsIWindowsRegKey> regKey =
+      do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+                        NS_LITERAL_STRING("Control Panel\\Desktop"),
+                        nsIWindowsRegKey::ACCESS_SET_VALUE);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-      // The size is always 3 unicode characters.
-      PRInt32 size = 3 * sizeof(PRUnichar);
-      ::RegSetValueExW(key, L"TileWallpaper",
-                       0, REG_SZ, (const BYTE *)tile, size);
-      ::RegSetValueExW(key, L"WallpaperStyle",
-                       0, REG_SZ, (const BYTE *)style, size);
-      ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
-                              SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
+    nsAutoString tile;
+    nsAutoString style;
+    switch (aPosition) {
+      case BACKGROUND_TILE:
+        style.AssignLiteral("0");
+        tile.AssignLiteral("1");
+        break;
+      case BACKGROUND_CENTER:
+        style.AssignLiteral("0");
+        tile.AssignLiteral("0");
+        break;
+      case BACKGROUND_STRETCH:
+        style.AssignLiteral("2");
+        tile.AssignLiteral("0");
+        break;
+    }
 
-      // Close the key we opened.
-      ::RegCloseKey(key);
-    }
+    rv = regKey->WriteStringValue(NS_LITERAL_STRING("TileWallpaper"), tile);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = regKey->WriteStringValue(NS_LITERAL_STRING("WallpaperStyle"), style);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = regKey->Close();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
+                            SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplication(PRInt32 aApplication)
 {
   nsAutoString application;
@@ -774,38 +770,34 @@ nsWindowsShellService::SetDesktopBackgro
   int aParameters[2] = { COLOR_BACKGROUND, COLOR_DESKTOP };
   BYTE r = (aColor >> 16);
   BYTE g = (aColor << 16) >> 24;
   BYTE b = (aColor << 24) >> 24;
   COLORREF colors[2] = { RGB(r,g,b), RGB(r,g,b) };
 
   ::SetSysColors(sizeof(aParameters) / sizeof(int), aParameters, colors);
 
-  bool result = false;
-  DWORD  dwDisp = 0;
-  HKEY   key;
-  // Try to create/open a subkey under HKCU.
-  DWORD rv = ::RegCreateKeyExW(HKEY_CURRENT_USER,
-                               L"Control Panel\\Colors", 0, NULL,
-                               REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
-                               &key, &dwDisp);
+  nsresult rv;
+  nsCOMPtr<nsIWindowsRegKey> regKey =
+    do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  if (REG_SUCCEEDED(rv)) {
-    char rgb[12];
-    sprintf((char*)rgb, "%u %u %u\0", r, g, b);
-    NS_ConvertUTF8toUTF16 backColor(rgb);
+  rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+                      NS_LITERAL_STRING("Control Panel\\Colors"),
+                      nsIWindowsRegKey::ACCESS_SET_VALUE);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-    ::RegSetValueExW(key, L"Background",
-                     0, REG_SZ, (const BYTE *)backColor.get(),
-                     (backColor.Length() + 1) * sizeof(PRUnichar));
-  }
-  
-  // Close the key we opened.
-  ::RegCloseKey(key);
-  return NS_OK;
+  PRUnichar rgb[12];
+  _snwprintf(rgb, 12, L"%u %u %u", r, g, b);
+
+  rv = regKey->WriteStringValue(NS_LITERAL_STRING("Background"),
+                                nsDependentString(rgb));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return regKey->Close();
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplicationWithURI(nsILocalFile* aApplication,
                                               const nsACString& aURI)
 {
   nsresult rv;
   nsCOMPtr<nsIProcess> process = 
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/binutils-deterministic.patch
@@ -0,0 +1,22 @@
+diff -ru a/binutils/ar.c b/binutils/ar.c
+--- a/binutils/ar.c	2011-03-16 04:35:58.000000000 -0400
++++ b/binutils/ar.c	2012-01-19 15:44:46.211226017 -0500
+@@ -98,7 +98,7 @@
+ /* Operate in deterministic mode: write zero for timestamps, uids,
+    and gids for archive members and the archive symbol table, and write
+    consistent file modes.  */
+-int deterministic = 0;
++int deterministic = TRUE;
+ 
+ /* Nonzero means it's the name of an existing member; position new or moved
+    files with respect to this one.  */
+@@ -634,9 +634,6 @@
+       if (newer_only && operation != replace)
+ 	fatal (_("`u' is only meaningful with the `r' option."));
+ 
+-      if (newer_only && deterministic)
+-	fatal (_("`u' is not meaningful with the `D' option."));
+-
+       if (postype != pos_default)
+ 	posname = argv[arg_index++];
+ 
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -35,22 +35,16 @@ def patch(patch, plevel, srcdir):
 
 def build_package(package_source_dir, package_build_dir, configure_args):
     os.mkdir(package_build_dir)
     run_in(package_build_dir,
            ["%s/configure" % package_source_dir] + configure_args)
     run_in(package_build_dir, ["make", "-j8"])
     run_in(package_build_dir, ["make", "install"])
 
-def build_binutils(base_dir, binutils_inst_dir):
-    binutils_build_dir = base_dir + '/binutils_build'
-    build_package(binutils_source_dir, binutils_build_dir,
-                  ["--prefix=%s" % binutils_inst_dir])
-
-# FIXME: factor this with build_binutils
 def build_tar(base_dir, tar_inst_dir):
     tar_build_dir = base_dir + '/tar_build'
     build_package(tar_source_dir, tar_build_dir,
                   ["--prefix=%s" % tar_inst_dir])
 
 def build_one_stage(env, stage_dir):
     old_env = os.environ.copy()
     os.environ.update(env)
@@ -66,20 +60,25 @@ def build_one_stage(env, stage_dir):
                   ["--prefix=%s" % lib_inst_dir, "--disable-shared",
                    "--with-gmp=%s" % lib_inst_dir])
     mpc_build_dir = stage_dir + '/mpc'
     build_package(mpc_source_dir, mpc_build_dir,
                   ["--prefix=%s" % lib_inst_dir, "--disable-shared",
                    "--with-gmp=%s" % lib_inst_dir,
                    "--with-mpfr=%s" % lib_inst_dir])
 
+    tool_inst_dir = stage_dir + '/inst'
+
+    binutils_build_dir = stage_dir + '/binutils'
+    build_package(binutils_source_dir, binutils_build_dir,
+                  ["--prefix=%s" % tool_inst_dir])
+
     gcc_build_dir = stage_dir + '/gcc'
-    gcc_inst_dir = stage_dir + '/inst'
     build_package(gcc_source_dir, gcc_build_dir,
-                  ["--prefix=%s" % gcc_inst_dir,
+                  ["--prefix=%s" % tool_inst_dir,
                    "--enable-__cxa_atexit",
                    "--with-gmp=%s" % lib_inst_dir,
                    "--with-mpfr=%s" % lib_inst_dir,
                    "--with-mpc=%s" % lib_inst_dir,
                    "--enable-languages=c,c++",
                    "--disable-bootstrap"])
     os.environ.clear()
     os.environ.update(old_env)
@@ -129,39 +128,37 @@ tar_source_dir  = build_source_dir('tar-
 mpc_source_dir  = build_source_dir('mpc-', mpc_version)
 mpfr_source_dir = build_source_dir('mpfr-', mpfr_version)
 gmp_source_dir  = build_source_dir('gmp-', gmp_version)
 gcc_source_dir  = build_source_dir('gcc-', gcc_version)
 
 if not os.path.exists(source_dir):
     os.mkdir(source_dir)
     extract(binutils_source_tar, source_dir)
+    patch('binutils-deterministic.patch', 1, binutils_source_dir)
     extract(tar_source_tar, source_dir)
     extract(mpc_source_tar, source_dir)
     extract(mpfr_source_tar, source_dir)
     extract(gmp_source_tar, source_dir)
     extract(gcc_source_tar, source_dir)
     patch('plugin_finish_decl.diff', 0, gcc_source_dir)
     patch('pr49911.diff', 1, gcc_source_dir)
     patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
 
 if os.path.exists(build_dir):
     shutil.rmtree(build_dir)
 os.mkdir(build_dir)
 
-tools_inst_dir = build_dir + '/tools_inst'
-build_binutils(build_dir, tools_inst_dir)
-build_tar(build_dir, tools_inst_dir)
-
-os.environ["AR"] = os.path.realpath('det-ar.sh')
-os.environ["MOZ_AR"] = tools_inst_dir + '/bin/ar'
-os.environ["RANLIB"] = "true"
+tar_inst_dir = build_dir + '/tar_inst'
+build_tar(build_dir, tar_inst_dir)
 
 stage1_dir = build_dir + '/stage1'
 build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir)
 
-stage1_gcc_inst_dir = stage1_dir + '/inst'
+stage1_tool_inst_dir = stage1_dir + '/inst'
 stage2_dir = build_dir + '/stage2'
-build_one_stage({"CC"  : stage1_gcc_inst_dir + "/bin/gcc",
-                 "CXX" : stage1_gcc_inst_dir + "/bin/g++"}, stage2_dir)
+build_one_stage({"CC"     : stage1_tool_inst_dir + "/bin/gcc",
+                 "CXX"    : stage1_tool_inst_dir + "/bin/g++",
+                 "AR"     : stage1_tool_inst_dir + "/bin/ar",
+                 "RANLIB" : "true" })
 
-build_tar_package(tools_inst_dir + "/bin/tar",
+build_tar_package(tar_inst_dir + "/bin/tar",
                   "toolchain.tar", stage2_dir, "inst")
deleted file mode 100755
--- a/build/unix/build-toolchain/det-ar.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-shift
-echo $MOZ_AR "crD" "$@"
-exec $MOZ_AR "crD" "$@"
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/plugin_finish_decl.diff
@@ -0,0 +1,179 @@
+Index: gcc/doc/plugins.texi
+===================================================================
+--- gcc/doc/plugins.texi	(revision 162126)
++++ gcc/doc/plugins.texi	(working copy)
+@@ -144,6 +144,7 @@
+ @{
+   PLUGIN_PASS_MANAGER_SETUP,    /* To hook into pass manager.  */
+   PLUGIN_FINISH_TYPE,           /* After finishing parsing a type.  */
++  PLUGIN_FINISH_DECL,           /* After finishing parsing a declaration. */
+   PLUGIN_FINISH_UNIT,           /* Useful for summary processing.  */
+   PLUGIN_PRE_GENERICIZE,        /* Allows to see low level AST in C and C++ frontends.  */
+   PLUGIN_FINISH,                /* Called before GCC exits.  */
+Index: gcc/plugin.def
+===================================================================
+--- gcc/plugin.def	(revision 162126)
++++ gcc/plugin.def	(working copy)
+@@ -24,6 +24,9 @@
+ /* After finishing parsing a type.  */
+ DEFEVENT (PLUGIN_FINISH_TYPE)
+ 
++/* After finishing parsing a declaration. */
++DEFEVENT (PLUGIN_FINISH_DECL)
++
+ /* Useful for summary processing.  */
+ DEFEVENT (PLUGIN_FINISH_UNIT)
+ 
+Index: gcc/testsuite/g++.dg/plugin/plugin.exp
+===================================================================
+--- gcc/testsuite/g++.dg/plugin/plugin.exp	(revision 162126)
++++ gcc/testsuite/g++.dg/plugin/plugin.exp	(working copy)
+@@ -51,7 +51,8 @@
+     { pragma_plugin.c pragma_plugin-test-1.C } \
+     { selfassign.c self-assign-test-1.C self-assign-test-2.C self-assign-test-3.C } \
+     { dumb_plugin.c dumb-plugin-test-1.C } \
+-    { header_plugin.c header-plugin-test.C } ]
++    { header_plugin.c header-plugin-test.C } \
++    { decl_plugin.c decl-plugin-test.C } ]
+ 
+ foreach plugin_test $plugin_test_list {
+     # Replace each source file with its full-path name
+Index: gcc/testsuite/g++.dg/plugin/decl-plugin-test.C
+===================================================================
+--- gcc/testsuite/g++.dg/plugin/decl-plugin-test.C	(revision 0)
++++ gcc/testsuite/g++.dg/plugin/decl-plugin-test.C	(revision 0)
+@@ -0,0 +1,32 @@
++
++
++extern int global; // { dg-warning "Decl Global global" }
++int global_array[] = { 1, 2, 3 }; // { dg-warning "Decl Global global_array" }
++
++int takes_args(int arg1, int arg2)
++{
++  int local = arg1 + arg2 + global; // { dg-warning "Decl Local local" }
++  return local + 1;
++}
++
++int global = 12; // { dg-warning "Decl Global global" }
++
++struct test_str {
++  int field; // { dg-warning "Decl Field field" }
++};
++
++class test_class {
++  int class_field1; // { dg-warning "Decl Field class_field1" }
++  int class_field2; // { dg-warning "Decl Field class_field2" }
++
++  test_class() // { dg-warning "Decl Function test_class" }
++    : class_field1(0), class_field2(0)
++  {}
++
++  void swap_fields(int bias) // { dg-warning "Decl Function swap_fields" }
++  {
++    int temp = class_field1 + bias; // { dg-warning "Decl Local temp" }
++    class_field1 = class_field2 - bias;
++    class_field2 = temp;
++  }
++};
+Index: gcc/testsuite/g++.dg/plugin/decl_plugin.c
+===================================================================
+--- gcc/testsuite/g++.dg/plugin/decl_plugin.c	(revision 0)
++++ gcc/testsuite/g++.dg/plugin/decl_plugin.c	(revision 0)
+@@ -0,0 +1,51 @@
++/* A plugin example that shows which declarations are caught by FINISH_DECL */
++
++#include "gcc-plugin.h"
++#include <stdlib.h>
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "tree.h"
++#include "tree-pass.h"
++#include "intl.h"
++
++int plugin_is_GPL_compatible;
++
++/* Callback function to invoke after GCC finishes a declaration. */
++
++void plugin_finish_decl (void *event_data, void *data)
++{
++  tree decl = (tree) event_data;
++
++  const char *kind = NULL;
++  switch (TREE_CODE(decl)) {
++  case FUNCTION_DECL:
++    kind = "Function"; break;
++  case PARM_DECL:
++    kind = "Parameter"; break;
++  case VAR_DECL:
++    if (DECL_CONTEXT(decl) != NULL)
++      kind = "Local";
++    else
++      kind = "Global";
++    break;
++  case FIELD_DECL:
++    kind = "Field"; break;
++  default:
++    kind = "Unknown";
++  }
++
++  warning (0, G_("Decl %s %s"),
++           kind, IDENTIFIER_POINTER (DECL_NAME (decl)));
++}
++
++int
++plugin_init (struct plugin_name_args *plugin_info,
++             struct plugin_gcc_version *version)
++{
++  const char *plugin_name = plugin_info->base_name;
++
++  register_callback (plugin_name, PLUGIN_FINISH_DECL,
++                     plugin_finish_decl, NULL);
++  return 0;
++}
+Index: gcc/cp/decl.c
+===================================================================
+--- gcc/cp/decl.c	(revision 162126)
++++ gcc/cp/decl.c	(working copy)
+@@ -5967,6 +5967,8 @@
+   /* If this was marked 'used', be sure it will be output.  */
+   if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+     mark_decl_referenced (decl);
++
++  invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
+ }
+ 
+ /* Returns a declaration for a VAR_DECL as if:
+Index: gcc/c-decl.c
+===================================================================
+--- gcc/c-decl.c	(revision 162126)
++++ gcc/c-decl.c	(working copy)
+@@ -4392,6 +4392,8 @@
+       && DECL_INITIAL (decl) == NULL_TREE)
+     warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
+ 		"uninitialized const %qD is invalid in C++", decl);
++
++  invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
+ }
+ 
+ /* Given a parsed parameter declaration, decode it into a PARM_DECL.  */
+Index: gcc/plugin.c
+===================================================================
+--- gcc/plugin.c	(revision 162126)
++++ gcc/plugin.c	(working copy)
+@@ -400,6 +400,7 @@
+ 	  }
+       /* Fall through.  */
+       case PLUGIN_FINISH_TYPE:
++      case PLUGIN_FINISH_DECL:
+       case PLUGIN_START_UNIT:
+       case PLUGIN_FINISH_UNIT:
+       case PLUGIN_PRE_GENERICIZE:
+@@ -481,6 +482,7 @@
+ 	gcc_assert (event < event_last);
+       /* Fall through.  */
+       case PLUGIN_FINISH_TYPE:
++      case PLUGIN_FINISH_DECL:
+       case PLUGIN_START_UNIT:
+       case PLUGIN_FINISH_UNIT:
+       case PLUGIN_PRE_GENERICIZE:
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/pr49911.diff
@@ -0,0 +1,274 @@
+diff -ru gcc-4.5.2/gcc/double-int.c gcc-4.5.2-new/gcc/double-int.c
+--- gcc-4.5.2/gcc/double-int.c	2009-11-25 05:55:54.000000000 -0500
++++ gcc-4.5.2-new/gcc/double-int.c	2011-11-29 10:20:27.625583810 -0500
+@@ -296,7 +296,12 @@
+ tree
+ double_int_to_tree (tree type, double_int cst)
+ {
+-  cst = double_int_ext (cst, TYPE_PRECISION (type), TYPE_UNSIGNED (type));
++  /* Size types *are* sign extended.  */
++  bool sign_extended_type = (!TYPE_UNSIGNED (type)
++			     || (TREE_CODE (type) == INTEGER_TYPE
++				 && TYPE_IS_SIZETYPE (type)));
++
++  cst = double_int_ext (cst, TYPE_PRECISION (type), !sign_extended_type);
+ 
+   return build_int_cst_wide (type, cst.low, cst.high);
+ }
+diff -ru gcc-4.5.2/gcc/tree.c gcc-4.5.2-new/gcc/tree.c
+--- gcc-4.5.2/gcc/tree.c	2010-07-07 11:24:27.000000000 -0400
++++ gcc-4.5.2-new/gcc/tree.c	2011-11-29 10:20:27.626583813 -0500
+@@ -9750,7 +9750,7 @@
+ tree
+ upper_bound_in_type (tree outer, tree inner)
+ {
+-  unsigned HOST_WIDE_INT lo, hi;
++  double_int high;
+   unsigned int det = 0;
+   unsigned oprec = TYPE_PRECISION (outer);
+   unsigned iprec = TYPE_PRECISION (inner);
+@@ -9797,18 +9797,18 @@
+   /* Compute 2^^prec - 1.  */
+   if (prec <= HOST_BITS_PER_WIDE_INT)
+     {
+-      hi = 0;
+-      lo = ((~(unsigned HOST_WIDE_INT) 0)
++      high.high = 0;
++      high.low = ((~(unsigned HOST_WIDE_INT) 0)
+ 	    >> (HOST_BITS_PER_WIDE_INT - prec));
+     }
+   else
+     {
+-      hi = ((~(unsigned HOST_WIDE_INT) 0)
++      high.high = ((~(unsigned HOST_WIDE_INT) 0)
+ 	    >> (2 * HOST_BITS_PER_WIDE_INT - prec));
+-      lo = ~(unsigned HOST_WIDE_INT) 0;
++      high.low = ~(unsigned HOST_WIDE_INT) 0;
+     }
+ 
+-  return build_int_cst_wide (outer, lo, hi);
++  return double_int_to_tree (outer, high);
+ }
+ 
+ /* Returns the smallest value obtainable by casting something in INNER type to
+diff -ru gcc-4.5.2/gcc/tree-vrp.c gcc-4.5.2-new/gcc/tree-vrp.c
+--- gcc-4.5.2/gcc/tree-vrp.c	2010-06-14 11:23:31.000000000 -0400
++++ gcc-4.5.2-new/gcc/tree-vrp.c	2011-11-29 10:20:27.628583820 -0500
+@@ -127,10 +127,10 @@
+ static inline tree
+ vrp_val_max (const_tree type)
+ {
+-  if (!INTEGRAL_TYPE_P (type))
+-    return NULL_TREE;
++  if (INTEGRAL_TYPE_P (type))
++    return upper_bound_in_type (CONST_CAST_TREE (type), CONST_CAST_TREE (type));
+ 
+-  return TYPE_MAX_VALUE (type);
++  return NULL_TREE;
+ }
+ 
+ /* Return the minimum value for TYPE.  */
+@@ -138,10 +138,10 @@
+ static inline tree
+ vrp_val_min (const_tree type)
+ {
+-  if (!INTEGRAL_TYPE_P (type))
+-    return NULL_TREE;
++  if (INTEGRAL_TYPE_P (type))
++    return lower_bound_in_type (CONST_CAST_TREE (type), CONST_CAST_TREE (type));
+ 
+-  return TYPE_MIN_VALUE (type);
++  return NULL_TREE;
+ }
+ 
+ /* Return whether VAL is equal to the maximum value of its type.  This
+@@ -539,7 +539,7 @@
+   set_value_range (vr, VR_RANGE, zero,
+ 		   (overflow_infinity
+ 		    ? positive_overflow_infinity (type)
+-		    : TYPE_MAX_VALUE (type)),
++		    : vrp_val_max (type)),
+ 		   vr->equiv);
+ }
+ 
+@@ -1595,7 +1595,7 @@
+     }
+   else if (cond_code == LE_EXPR || cond_code == LT_EXPR)
+     {
+-      min = TYPE_MIN_VALUE (type);
++      min = vrp_val_min (type);
+ 
+       if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+ 	max = limit;
+@@ -1630,7 +1630,7 @@
+     }
+   else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
+     {
+-      max = TYPE_MAX_VALUE (type);
++      max = vrp_val_max (type);
+ 
+       if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+ 	min = limit;
+@@ -2047,11 +2047,11 @@
+ 	  || code == ROUND_DIV_EXPR)
+ 	return (needs_overflow_infinity (TREE_TYPE (res))
+ 		? positive_overflow_infinity (TREE_TYPE (res))
+-		: TYPE_MAX_VALUE (TREE_TYPE (res)));
++		: vrp_val_max (TREE_TYPE (res)));
+       else
+ 	return (needs_overflow_infinity (TREE_TYPE (res))
+ 		? negative_overflow_infinity (TREE_TYPE (res))
+-		: TYPE_MIN_VALUE (TREE_TYPE (res)));
++		: vrp_val_min (TREE_TYPE (res)));
+     }
+ 
+   return res;
+@@ -2750,8 +2750,8 @@
+ 	  && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
+ 	{
+ 	  vr0.type = VR_RANGE;
+-	  vr0.min = TYPE_MIN_VALUE (inner_type);
+-	  vr0.max = TYPE_MAX_VALUE (inner_type);
++	  vr0.min = vrp_val_min (inner_type);
++	  vr0.max = vrp_val_max (inner_type);
+ 	}
+ 
+       /* If VR0 is a constant range or anti-range and the conversion is
+@@ -2836,7 +2836,7 @@
+ 	    }
+ 	}
+       else
+-	min = TYPE_MIN_VALUE (type);
++	min = vrp_val_min (type);
+ 
+       if (is_positive_overflow_infinity (vr0.min))
+ 	max = negative_overflow_infinity (type);
+@@ -2855,7 +2855,7 @@
+ 	    }
+ 	}
+       else
+-	max = TYPE_MIN_VALUE (type);
++	max = vrp_val_min (type);
+     }
+   else if (code == NEGATE_EXPR
+ 	   && TYPE_UNSIGNED (type))
+@@ -2897,7 +2897,7 @@
+       else if (!vrp_val_is_min (vr0.min))
+ 	min = fold_unary_to_constant (code, type, vr0.min);
+       else if (!needs_overflow_infinity (type))
+-	min = TYPE_MAX_VALUE (type);
++	min = vrp_val_max (type);
+       else if (supports_overflow_infinity (type))
+ 	min = positive_overflow_infinity (type);
+       else
+@@ -2911,7 +2911,7 @@
+       else if (!vrp_val_is_min (vr0.max))
+ 	max = fold_unary_to_constant (code, type, vr0.max);
+       else if (!needs_overflow_infinity (type))
+-	max = TYPE_MAX_VALUE (type);
++	max = vrp_val_max (type);
+       else if (supports_overflow_infinity (type)
+ 	       /* We shouldn't generate [+INF, +INF] as set_value_range
+ 		  doesn't like this and ICEs.  */
+@@ -2941,7 +2941,7 @@
+ 	         TYPE_MIN_VALUE, remember -TYPE_MIN_VALUE = TYPE_MIN_VALUE.  */
+ 	      if (TYPE_OVERFLOW_WRAPS (type))
+ 		{
+-		  tree type_min_value = TYPE_MIN_VALUE (type);
++		  tree type_min_value = vrp_val_min (type);
+ 
+ 		  min = (vr0.min != type_min_value
+ 			 ? int_const_binop (PLUS_EXPR, type_min_value,
+@@ -2953,7 +2953,7 @@
+ 		  if (overflow_infinity_range_p (&vr0))
+ 		    min = negative_overflow_infinity (type);
+ 		  else
+-		    min = TYPE_MIN_VALUE (type);
++		    min = vrp_val_min (type);
+ 		}
+ 	    }
+ 	  else
+@@ -2974,7 +2974,7 @@
+ 		    }
+ 		}
+ 	      else
+-		max = TYPE_MAX_VALUE (type);
++		max = vrp_val_max (type);
+ 	    }
+ 	}
+ 
+@@ -3258,11 +3258,11 @@
+   if (POINTER_TYPE_P (type) || !TYPE_MIN_VALUE (type))
+     tmin = lower_bound_in_type (type, type);
+   else
+-    tmin = TYPE_MIN_VALUE (type);
++    tmin = vrp_val_min (type);
+   if (POINTER_TYPE_P (type) || !TYPE_MAX_VALUE (type))
+     tmax = upper_bound_in_type (type, type);
+   else
+-    tmax = TYPE_MAX_VALUE (type);
++    tmax = vrp_val_max (type);
+ 
+   if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+     {
+@@ -4146,8 +4146,8 @@
+   if ((comp_code == GT_EXPR || comp_code == LT_EXPR)
+       && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+     {
+-      tree min = TYPE_MIN_VALUE (TREE_TYPE (val));
+-      tree max = TYPE_MAX_VALUE (TREE_TYPE (val));
++      tree min = vrp_val_min (TREE_TYPE (val));
++      tree max = vrp_val_max (TREE_TYPE (val));
+ 
+       if (comp_code == GT_EXPR
+ 	  && (!max
+@@ -6426,13 +6426,13 @@
+ 		 VARYING.  Same if the previous max value was invalid for
+ 		 the type and we'd end up with vr_result.min > vr_result.max.  */
+ 	      if (vrp_val_is_max (vr_result.max)
+-		  || compare_values (TYPE_MIN_VALUE (TREE_TYPE (vr_result.min)),
++		  || compare_values (vrp_val_min (TREE_TYPE (vr_result.min)),
+ 				     vr_result.max) > 0)
+ 		goto varying;
+ 
+ 	      if (!needs_overflow_infinity (TREE_TYPE (vr_result.min))
+ 		  || !vrp_var_may_overflow (lhs, phi))
+-		vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min));
++		vr_result.min = vrp_val_min (TREE_TYPE (vr_result.min));
+ 	      else if (supports_overflow_infinity (TREE_TYPE (vr_result.min)))
+ 		vr_result.min =
+ 		  negative_overflow_infinity (TREE_TYPE (vr_result.min));
+@@ -6448,13 +6448,13 @@
+ 		 VARYING.  Same if the previous min value was invalid for
+ 		 the type and we'd end up with vr_result.max < vr_result.min.  */
+ 	      if (vrp_val_is_min (vr_result.min)
+-		  || compare_values (TYPE_MAX_VALUE (TREE_TYPE (vr_result.max)),
++		  || compare_values (vrp_val_max (TREE_TYPE (vr_result.max)),
+ 				     vr_result.min) < 0)
+ 		goto varying;
+ 
+ 	      if (!needs_overflow_infinity (TREE_TYPE (vr_result.max))
+ 		  || !vrp_var_may_overflow (lhs, phi))
+-		vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max));
++		vr_result.max = vrp_val_max (TREE_TYPE (vr_result.max));
+ 	      else if (supports_overflow_infinity (TREE_TYPE (vr_result.max)))
+ 		vr_result.max =
+ 		  positive_overflow_infinity (TREE_TYPE (vr_result.max));
+@@ -6782,7 +6782,7 @@
+     {
+       /* This should not be negative infinity; there is no overflow
+ 	 here.  */
+-      min = TYPE_MIN_VALUE (TREE_TYPE (op0));
++      min = vrp_val_min (TREE_TYPE (op0));
+ 
+       max = op1;
+       if (cond_code == LT_EXPR && !is_overflow_infinity (max))
+@@ -6797,7 +6797,7 @@
+     {
+       /* This should not be positive infinity; there is no overflow
+ 	 here.  */
+-      max = TYPE_MAX_VALUE (TREE_TYPE (op0));
++      max = vrp_val_max (TREE_TYPE (op0));
+ 
+       min = op1;
+       if (cond_code == GT_EXPR && !is_overflow_infinity (min))
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/r159628-r163231-r171807.patch
@@ -0,0 +1,98 @@
+diff -ru gcc-4.5.2/libstdc++-v3/include/bits/stl_pair.h gcc-4.5.2-new/libstdc++-v3/include/bits/stl_pair.h
+--- gcc-4.5.2/libstdc++-v3/include/bits/stl_pair.h	2010-06-10 06:26:14.000000000 -0400
++++ gcc-4.5.2-new/libstdc++-v3/include/bits/stl_pair.h	2011-11-29 10:25:51.203597393 -0500
+@@ -88,6 +88,8 @@
+       : first(__a), second(__b) { }
+ 
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
++      pair(const pair&) = default;
++
+       // DR 811.
+       template<class _U1, class = typename
+ 	       std::enable_if<std::is_convertible<_U1, _T1>::value>::type>
+@@ -131,6 +133,15 @@
+ 
+       template<class _U1, class _U2>
+         pair&
++        operator=(const pair<_U1, _U2>& __p)
++	{
++	  first = __p.first;
++	  second = __p.second;
++	  return *this;
++	}
++
++      template<class _U1, class _U2>
++        pair&
+         operator=(pair<_U1, _U2>&& __p)
+ 	{
+ 	  first = std::move(__p.first);
+diff -ru gcc-4.5.2/libstdc++-v3/include/bits/stl_queue.h gcc-4.5.2-new/libstdc++-v3/include/bits/stl_queue.h
+--- gcc-4.5.2/libstdc++-v3/include/bits/stl_queue.h	2010-02-04 13:20:34.000000000 -0500
++++ gcc-4.5.2-new/libstdc++-v3/include/bits/stl_queue.h	2011-11-29 10:26:22.511695475 -0500
+@@ -1,6 +1,6 @@
+ // Queue implementation -*- C++ -*-
+ 
+-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
++// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ // Free Software Foundation, Inc.
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+@@ -137,16 +137,6 @@
+       explicit
+       queue(_Sequence&& __c = _Sequence())
+       : c(std::move(__c)) { }
+-
+-      queue(queue&& __q)
+-      : c(std::move(__q.c)) { }
+-
+-      queue&
+-      operator=(queue&& __q)
+-      {
+-	c = std::move(__q.c);
+-	return *this;
+-      }
+ #endif
+ 
+       /**
+@@ -451,17 +441,6 @@
+ 	  c.insert(c.end(), __first, __last);
+ 	  std::make_heap(c.begin(), c.end(), comp);
+ 	}
+-
+-      priority_queue(priority_queue&& __pq)
+-      : c(std::move(__pq.c)), comp(std::move(__pq.comp)) { }
+-
+-      priority_queue&
+-      operator=(priority_queue&& __pq)
+-      {
+-	c = std::move(__pq.c);
+-	comp = std::move(__pq.comp);
+-	return *this;
+-      }
+ #endif
+ 
+       /**
+diff -ru gcc-4.5.2/libstdc++-v3/libsupc++/exception_ptr.h gcc-4.5.2-new/libstdc++-v3/libsupc++/exception_ptr.h
+--- gcc-4.5.2/libstdc++-v3/libsupc++/exception_ptr.h	2009-11-09 17:09:30.000000000 -0500
++++ gcc-4.5.2-new/libstdc++-v3/libsupc++/exception_ptr.h	2011-11-29 10:26:10.878659023 -0500
+@@ -129,7 +129,7 @@
+       operator==(const exception_ptr&, const exception_ptr&) throw() 
+       __attribute__ ((__pure__));
+ 
+-      const type_info*
++      const class type_info*
+       __cxa_exception_type() const throw() __attribute__ ((__pure__));
+     };
+ 
+diff -ru gcc-4.5.2/libstdc++-v3/libsupc++/nested_exception.h gcc-4.5.2-new/libstdc++-v3/libsupc++/nested_exception.h
+--- gcc-4.5.2/libstdc++-v3/libsupc++/nested_exception.h	2010-02-18 12:20:16.000000000 -0500
++++ gcc-4.5.2-new/libstdc++-v3/libsupc++/nested_exception.h	2011-11-29 10:26:10.879659026 -0500
+@@ -119,7 +119,7 @@
+   // with a type that has an accessible nested_exception base.
+   template<typename _Ex>
+     inline void
+-    __throw_with_nested(_Ex&& __ex, const nested_exception* = 0)
++    __throw_with_nested(_Ex&& __ex, const nested_exception*)
+     { throw __ex; }
+ 
+   template<typename _Ex>
--- a/config/config.mk
+++ b/config/config.mk
@@ -773,18 +773,18 @@ OPTIMIZE_JARS_CMD = $(PYTHON) $(call cor
 CREATE_PRECOMPLETE_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/createprecomplete.py)
 
 EXPAND_LIBS = $(PYTHON) -I$(DEPTH)/config $(topsrcdir)/config/expandlibs.py
 EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist -- $(MKSHLIB)
+EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
+EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -43,16 +43,20 @@ With the --extract argument (useful for 
 from static libraries (or use those listed in library descriptors directly).
 
 With the --uselist argument (useful for e.g. $(CC)), it replaces all object
 files with a list file. This can be used to avoid limitations in the length
 of a command line. The kind of list file format used depends on the
 EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
 or 'linkerscript' for GNU ld linker scripts.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
+
+With the --reorder argument, followed by a file name, it will reorder the
+object files from the command line according to the order given in the file.
+Implies --extract.
 '''
 from __future__ import with_statement
 import sys
 import os
 from expandlibs import ExpandArgs, relativize
 import expandlibs_config as conf
 from optparse import OptionParser
 import subprocess
@@ -120,30 +124,51 @@ class ExpandArgsMore(ExpandArgs):
         self.tmp.append(tmp)
         f = os.fdopen(fd, "w")
         f.writelines(content)
         f.close()
         idx = self.index(objs[0])
         newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
         self[0:] = newlist
 
+    def reorder(self, order_list):
+        '''Given a list of file names without OBJ_SUFFIX, rearrange self
+        so that the object file names it contains are ordered according to
+        that list.
+        '''
+        objs = [o for o in self if o.endswith(conf.OBJ_SUFFIX)]
+        if not objs: return
+        idx = self.index(objs[0])
+        # Keep everything before the first object, then the ordered objects,
+        # then any other objects, then any non-objects after the first object
+        objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
+        self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
+                   [o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
+                   [x for x in self[idx:] if not x.endswith(conf.OBJ_SUFFIX)]
+
+
 def main():
     parser = OptionParser()
     parser.add_option("--extract", action="store_true", dest="extract",
         help="when a library has no descriptor file, extract it first, when possible")
     parser.add_option("--uselist", action="store_true", dest="uselist",
         help="use a list file for objects when executing a command")
     parser.add_option("--verbose", action="store_true", dest="verbose",
         help="display executed command and temporary files content")
+    parser.add_option("--reorder", dest="reorder",
+        help="reorder the objects according to the given list", metavar="FILE")
 
     (options, args) = parser.parse_args()
 
     with ExpandArgsMore(args) as args:
-        if options.extract:
+        if options.extract or options.reorder:
             args.extract()
+        if options.reorder:
+            with open(options.reorder) as file:
+                args.reorder([l.strip() for l in file.readlines()])
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print >>sys.stderr, "Executing: " + " ".join(args)
             for tmp in [f for f in args.tmp if os.path.isfile(f)]:
                 print >>sys.stderr, tmp + ":"
                 with open(tmp) as file:
--- a/config/tests/unit-expandlibs.py
+++ b/config/tests/unit-expandlibs.py
@@ -262,10 +262,33 @@ class TestExpandArgsMore(TestExpandInit)
 
             tmp = args.tmp
         # Check that all temporary files are properly removed
         self.assertEqual(True, all([not os.path.exists(f) for f in tmp]))
 
         # Restore subprocess.call
         subprocess.call = subprocess_call
 
+    def test_reorder(self):
+        '''Test object reordering'''
+        # We don't care about AR_EXTRACT testing, which is done in test_extract
+        config.AR_EXTRACT = ''
+
+        # ExpandArgsMore does the same as ExpandArgs
+        with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
+            self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files) 
+
+            # Use an order containing object files from libraries
+            order_files = [self.libx_files[1], self.libx_files[0], self.liby_files[2], self.files[1]]
+            order = [os.path.splitext(os.path.basename(f))[0] for f in order_files]
+            args.reorder(order[:2] + ['unknown'] + order[2:])
+
+            # self.files has objects at #1, #2, #4
+            self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1])
+            self.assertRelEqual(args[3:7], order_files)
+            self.assertRelEqual(args[7:9], [self.files[2], self.files[4]])
+            self.assertRelEqual(args[9:11], self.liby_files[:2])
+            self.assertRelEqual(args[11:12], [self.libx_files[2]])
+            self.assertRelEqual(args[12:14], [self.files[3], self.files[5]])
+            self.assertRelEqual(args[14:], [self.liby_files[3]])
+
 if __name__ == '__main__':
     unittest.main(testRunner=MozTestRunner())
--- a/configure.in
+++ b/configure.in
@@ -4904,17 +4904,19 @@ cairo-android)
     AC_DEFINE(MOZ_WIDGET_ANDROID)
     AC_DEFINE(MOZ_TOUCH)
     MOZ_WIDGET_TOOLKIT=android
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
     MOZ_INSTRUMENT_EVENT_LOOP=1
-    MOZ_OLD_LINKER=1
+    if test "$MOZ_BUILD_APP" = "mobile/xul"; then
+        MOZ_OLD_LINKER=1
+    fi
     MOZ_TOUCH=1
     ;;
 
 cairo-gonk)
     AC_DEFINE(MOZ_WIDGET_GONK)
     MOZ_WIDGET_TOOLKIT=gonk
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
@@ -7154,16 +7156,19 @@ elif test "${OS_TARGET}" = "WINNT" -o "$
   MOZ_GLUE_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
 else
   dnl On other Unix systems, we only want to link executables against mozglue
   MOZ_GLUE_PROGRAM_LDFLAGS='$(MKSHLIB_FORCE_ALL) $(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib) $(MKSHLIB_UNFORCE_ALL)'
   if test -n "$GNU_CC"; then
     dnl And we need mozglue symbols to be exported.
     MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS -rdynamic"
   fi
+  if test "$MOZ_LINKER" = 1; then
+    MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS $ZLIB_LIBS"
+  fi
 fi
 
 if test -z "$MOZ_MEMORY"; then
   case "${target}" in
     *-mingw*)
       if test -z "$WIN32_REDIST_DIR" -a -z "$MOZ_DEBUG"; then
         AC_MSG_WARN([When not building jemalloc, you need to set WIN32_REDIST_DIR to the path to the Visual C++ Redist (usually VCINSTALLDIR\redist\x86\Microsoft.VC80.CRT, for VC++ v8) if you intend to distribute your build.])
       fi
@@ -9043,17 +9048,27 @@ if test -z "$MOZ_NATIVE_NSPR"; then
         ac_configure_args="$ac_configure_args --disable-optimize"
     fi
     if test -n "$HAVE_64BIT_OS"; then
         ac_configure_args="$ac_configure_args --enable-64bit"
     fi
     if test -n "$USE_ARM_KUSER"; then
         ac_configure_args="$ac_configure_args --with-arm-kuser"
     fi
+    if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no ; then
+      # dladdr is supported by the new linker, even when the system linker doesn't
+      # support it. Trick nspr into using dladdr when it's not supported.
+      _SAVE_CPPFLAGS="$CPPFLAGS"
+      export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
+    fi
     AC_OUTPUT_SUBDIRS(nsprpub)
+    if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no; then
+      unset CPPFLAGS
+      CPPFLAGS="$_SAVE_CFLAGS"
+    fi
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     # Hack to deal with the fact that we use NSPR_CFLAGS everywhere
     AC_MSG_WARN([Recreating autoconf.mk with updated nspr-config output])
     if test "$OS_ARCH" != "WINNT"; then
        NSPR_LIBS=`./nsprpub/config/nspr-config --prefix=$LIBXUL_DIST --exec-prefix=$MOZ_BUILD_ROOT/dist --libdir=$LIBXUL_DIST/lib --libs`
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -74,19 +74,24 @@ static fp_except_t oldmask = fpsetmask(~
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMEvent.h"
 #include "nsTArray.h"
 #include "nsTextFragment.h"
 #include "nsReadableUtils.h"
 #include "nsINode.h"
 #include "nsHashtable.h"
 #include "nsIDOMNode.h"
-#include "nsHtml5Parser.h"
+#include "nsHtml5StringParser.h"
+#include "nsIParser.h"
+#include "nsIDocument.h"
 #include "nsIFragmentContentSink.h"
+#include "nsContentSink.h"
 #include "nsMathUtils.h"
+#include "nsThreadUtils.h"
+#include "nsIContent.h"
 #include "nsCharSeparatedTokenizer.h"
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/TimeStamp.h"
 
 struct nsNativeKeyEvent; // Don't include nsINativeKeyBindings.h here: it will force strange compilation error!
 
@@ -1039,17 +1044,18 @@ public:
    * @param aTargetNode the target container
    * @param aContextLocalName local name of context node
    * @param aContextNamespace namespace of context node
    * @param aQuirks true to make <table> not close <p>
    * @param aPreventScriptExecution true to prevent scripts from executing;
    *        don't set to false when parsing into a target node that has been
    *        bound to tree.
    * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
-   *         fragments is made and NS_OK otherwise.
+   *         fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
+   *         long and NS_OK otherwise.
    */
   static nsresult ParseFragmentHTML(const nsAString& aSourceBuffer,
                                     nsIContent* aTargetNode,
                                     nsIAtom* aContextLocalName,
                                     PRInt32 aContextNamespace,
                                     bool aQuirks,
                                     bool aPreventScriptExecution);
 
@@ -1066,16 +1072,30 @@ public:
    */
   static nsresult ParseFragmentXML(const nsAString& aSourceBuffer,
                                    nsIDocument* aDocument,
                                    nsTArray<nsString>& aTagStack,
                                    bool aPreventScriptExecution,
                                    nsIDOMDocumentFragment** aReturn);
 
   /**
+   * Parse a string into a document using the HTML parser.
+   * Script elements are marked unexecutable.
+   *
+   * @param aSourceBuffer the string to parse as an HTML document
+   * @param aTargetDocument the document object to parse into. Must not have
+   *                        child nodes.
+   * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
+   *         fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
+   *         long and NS_OK otherwise.
+   */
+  static nsresult ParseDocumentHTML(const nsAString& aSourceBuffer,
+                                    nsIDocument* aTargetDocument);
+
+  /**
    * Creates a new XML document, which is marked to be loaded as data.
    *
    * @param aNamespaceURI Namespace for the root element to create and insert in
    *                      the document. Only used if aQualifiedName is not
    *                      empty.
    * @param aQualifiedName Qualified name for the root element to create and
    *                       insert in the document. If empty no root element will
    *                       be created.
@@ -1934,17 +1954,17 @@ private:
 
   static bool sIsHandlingKeyBoardEvent;
   static bool sAllowXULXBL_for_file;
   static bool sIsFullScreenApiEnabled;
   static bool sTrustedFullScreenOnly;
   static bool sFullScreenKeyInputRestricted;
   static PRUint32 sHandlingInputTimeout;
 
-  static nsHtml5Parser* sHTMLFragmentParser;
+  static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   /**
    * True if there's a fragment parser activation on the stack.
    */
   static bool sFragmentParsingActive;
 
--- a/content/base/public/nsIScriptElement.h
+++ b/content/base/public/nsIScriptElement.h
@@ -44,18 +44,18 @@
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
 #include "nsWeakPtr.h"
 #include "nsIParser.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIDOMHTMLScriptElement.h"
 
 #define NS_ISCRIPTELEMENT_IID \
-{ 0x5bb3b905, 0x5988, 0x476f, \
-  { 0x95, 0x4f, 0x99, 0x02, 0x59, 0x82, 0x24, 0x67 } }
+{ 0x24ab3ff2, 0xd75e, 0x4be4, \
+  { 0x8d, 0x50, 0xd6, 0x75, 0x31, 0x29, 0xab, 0x65 } }
 
 /**
  * Internal interface implemented by script elements
  */
 class nsIScriptElement : public nsIScriptLoaderObserver {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
 
@@ -182,16 +182,38 @@ public:
   }
 
   void SetCreatorParser(nsIParser* aParser)
   {
     mCreatorParser = getter_AddRefs(NS_GetWeakReference(aParser));
   }
 
   /**
+   * Unblocks the creator parser
+   */
+  void UnblockParser()
+  {
+    nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
+    if (parser) {
+      parser->UnblockParser();
+    }
+  }
+
+  /**
+   * Attempts to resume parsing asynchronously
+   */
+  void ContinueParserAsync()
+  {
+    nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
+    if (parser) {
+      parser->ContinueInterruptedParsingAsync();
+    }
+  }
+
+  /**
    * Informs the creator parser that the evaluation of this script is starting
    */
   void BeginEvaluating()
   {
     nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
     if (parser) {
       parser->BeginEvaluatingParserInsertedScript();
     }
--- a/content/base/src/mozSanitizingSerializer.h
+++ b/content/base/src/mozSanitizingSerializer.h
@@ -98,17 +98,17 @@ public:
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
   // nsIContentSink
   NS_IMETHOD WillParse(void) { return NS_OK; }
   NS_IMETHOD WillInterrupt(void) { return NS_OK; }
   NS_IMETHOD WillResume(void) { return NS_OK; }
-  NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
   NS_IMETHOD AddComment(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode)
                                                     { return NS_OK; }
   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode);
   virtual void FlushPendingNotifications(mozFlushType aType) { }
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -104,98 +104,44 @@
 #include "nsISupportsPrimitives.h"
 #include "mozilla/Preferences.h"
 #include "nsParserConstants.h"
 
 using namespace mozilla;
 
 PRLogModuleInfo* gContentSinkLogModuleInfo;
 
-class nsScriptLoaderObserverProxy : public nsIScriptLoaderObserver
-{
-public:
-  nsScriptLoaderObserverProxy(nsIScriptLoaderObserver* aInner)
-    : mInner(do_GetWeakReference(aInner))
-  {
-  }
-  virtual ~nsScriptLoaderObserverProxy()
-  {
-  }
-  
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSISCRIPTLOADEROBSERVER
-
-  nsWeakPtr mInner;
-};
-
-NS_IMPL_ISUPPORTS1(nsScriptLoaderObserverProxy, nsIScriptLoaderObserver)
-
-NS_IMETHODIMP
-nsScriptLoaderObserverProxy::ScriptAvailable(nsresult aResult,
-                                             nsIScriptElement *aElement,
-                                             bool aIsInline,
-                                             nsIURI *aURI,
-                                             PRInt32 aLineNo)
-{
-  nsCOMPtr<nsIScriptLoaderObserver> inner = do_QueryReferent(mInner);
-
-  if (inner) {
-    return inner->ScriptAvailable(aResult, aElement, aIsInline, aURI,
-                                  aLineNo);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsScriptLoaderObserverProxy::ScriptEvaluated(nsresult aResult,
-                                             nsIScriptElement *aElement,
-                                             bool aIsInline)
-{
-  nsCOMPtr<nsIScriptLoaderObserver> inner = do_QueryReferent(mInner);
-
-  if (inner) {
-    return inner->ScriptEvaluated(aResult, aElement, aIsInline);
-  }
-
-  return NS_OK;
-}
-
-
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsIScriptLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptLoaderObserver)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
   if (tmp->mDocument) {
     tmp->mDocument->RemoveObserver(tmp);
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParser)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNodeInfoManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptLoader)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mScriptElements)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
                                                   nsNodeInfoManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mScriptElements)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 nsContentSink::nsContentSink()
 {
   // We have a zeroing operator new
   NS_ASSERTION(!mLayoutStarted, "What?");
   NS_ASSERTION(!mDynamicLowerValue, "What?");
@@ -230,17 +176,16 @@ PRInt32 nsContentSink::sInteractiveDefle
 PRInt32 nsContentSink::sPerfDeflectCount;
 PRInt32 nsContentSink::sPendingEventMode;
 PRInt32 nsContentSink::sEventProbeRate;
 PRInt32 nsContentSink::sInteractiveParseTime;
 PRInt32 nsContentSink::sPerfParseTime;
 PRInt32 nsContentSink::sInteractiveTime;
 PRInt32 nsContentSink::sInitialPerfTime;
 PRInt32 nsContentSink::sEnablePerfMode;
-bool    nsContentSink::sCanInterruptParser;
 
 void
 nsContentSink::InitializeStatics()
 {
   Preferences::AddBoolVarCache(&sNotifyOnTimer,
                                "content.notify.ontimer", true);
   // -1 means never.
   Preferences::AddIntVarCache(&sBackoffCount,
@@ -267,18 +212,16 @@ nsContentSink::InitializeStatics()
   Preferences::AddIntVarCache(&sPerfParseTime,
                               "content.sink.perf_parse_time", 360000);
   Preferences::AddIntVarCache(&sInteractiveTime,
                               "content.sink.interactive_time", 750000);
   Preferences::AddIntVarCache(&sInitialPerfTime,
                               "content.sink.initial_perf_time", 2000000);
   Preferences::AddIntVarCache(&sEnablePerfMode,
                               "content.sink.enable_perf_mode", 0);
-  Preferences::AddBoolVarCache(&sCanInterruptParser,
-                               "content.interrupt.parsing", true);
 }
 
 nsresult
 nsContentSink::Init(nsIDocument* aDoc,
                     nsIURI* aURI,
                     nsISupports* aContainer,
                     nsIChannel* aChannel)
 {
@@ -290,58 +233,47 @@ nsContentSink::Init(nsIDocument* aDoc,
   }
 
   mDocument = aDoc;
 
   mDocumentURI = aURI;
   mDocShell = do_QueryInterface(aContainer);
   mScriptLoader = mDocument->ScriptLoader();
 
-  if (!mFragmentMode) {
+  if (!mRunsToCompletion) {
     if (mDocShell) {
       PRUint32 loadType = 0;
       mDocShell->GetLoadType(&loadType);
       mDocument->SetChangeScrollPosWhenScrollingToRef(
         (loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
     }
 
-    // use this to avoid a circular reference sink->document->scriptloader->sink
-    nsCOMPtr<nsIScriptLoaderObserver> proxy =
-      new nsScriptLoaderObserverProxy(this);
-    NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
-
-    mScriptLoader->AddObserver(proxy);
-
     ProcessHTTPHeaders(aChannel);
   }
 
   mCSSLoader = aDoc->CSSLoader();
 
   mNodeInfoManager = aDoc->NodeInfoManager();
 
   mBackoffCount = sBackoffCount;
 
   if (sEnablePerfMode != 0) {
     mDynamicLowerValue = sEnablePerfMode == 1;
     FavorPerformanceHint(!mDynamicLowerValue, 0);
   }
 
-  // prevent DropParserAndPerfHint from unblocking onload in the fragment
-  // case
-  mCanInterruptParser = !mFragmentMode && sCanInterruptParser;
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
                                 bool aWasAlternate,
                                 nsresult aStatus)
 {
-  NS_ASSERTION(!mFragmentMode, "How come a fragment parser observed sheets?");
+  NS_ASSERTION(!mRunsToCompletion, "How come a fragment parser observed sheets?");
   if (!aWasAlternate) {
     NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
     --mPendingSheetCount;
 
     if (mPendingSheetCount == 0 &&
         (mDeferredLayoutStart || mDeferredFlushTags)) {
       if (mDeferredFlushTags) {
         FlushTags();
@@ -361,100 +293,16 @@ nsContentSink::StyleSheetLoaded(nsCSSSty
     }
     
     mScriptLoader->RemoveExecuteBlocker();
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsContentSink::ScriptAvailable(nsresult aResult,
-                               nsIScriptElement *aElement,
-                               bool aIsInline,
-                               nsIURI *aURI,
-                               PRInt32 aLineNo)
-{
-  PRUint32 count = mScriptElements.Count();
-
-  // aElement will not be in mScriptElements if a <script> was added
-  // using the DOM during loading or if DoneAddingChildren did not return
-  // NS_ERROR_HTMLPARSER_BLOCK.
-  NS_ASSERTION(count == 0 ||
-               mScriptElements.IndexOf(aElement) == PRInt32(count - 1) ||
-               mScriptElements.IndexOf(aElement) == -1,
-               "script found at unexpected position");
-
-  // Check if this is the element we were waiting for
-  if (count == 0 || aElement != mScriptElements[count - 1]) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(!aElement->GetScriptDeferred(), "defer script was in mScriptElements");
-  NS_ASSERTION(!aElement->GetScriptAsync(), "async script was in mScriptElements");
-
-  if (mParser && !mParser->IsParserEnabled()) {
-    // make sure to unblock the parser before evaluating the script,
-    // we must unblock the parser even if loading the script failed or
-    // if the script was empty, if we don't, the parser will never be
-    // unblocked.
-    mParser->UnblockParser();
-  }
-
-  if (NS_SUCCEEDED(aResult)) {
-    PreEvaluateScript();
-  } else {
-    mScriptElements.RemoveObjectAt(count - 1);
-
-    if (mParser && aResult != NS_BINDING_ABORTED) {
-      // Loading external script failed!. So, resume parsing since the parser
-      // got blocked when loading external script. See
-      // http://bugzilla.mozilla.org/show_bug.cgi?id=94903.
-      //
-      // XXX We don't resume parsing if we get NS_BINDING_ABORTED from the
-      //     script load, assuming that that error code means that the user
-      //     stopped the load through some action (like clicking a link). See
-      //     http://bugzilla.mozilla.org/show_bug.cgi?id=243392.
-      ContinueInterruptedParsingAsync();
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsContentSink::ScriptEvaluated(nsresult aResult,
-                               nsIScriptElement *aElement,
-                               bool aIsInline)
-{
-  mDeflectedCount = sPerfDeflectCount;
-
-  // Check if this is the element we were waiting for
-  PRInt32 count = mScriptElements.Count();
-  if (count == 0 || aElement != mScriptElements[count - 1]) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(!aElement->GetScriptDeferred(), "defer script was in mScriptElements");
-  NS_ASSERTION(!aElement->GetScriptAsync(), "async script was in mScriptElements");
-
-  // Pop the script element stack
-  mScriptElements.RemoveObjectAt(count - 1); 
-
-  if (NS_SUCCEEDED(aResult)) {
-    PostEvaluateScript(aElement);
-  }
-
-  if (mParser && mParser->IsParserEnabled()) {
-    ContinueInterruptedParsingAsync();
-  }
-
-  return NS_OK;
-}
-
 nsresult
 nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel)
 {
   nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(aChannel));
   
   if (!httpchannel) {
     return NS_OK;
   }
@@ -879,20 +727,20 @@ nsContentSink::ProcessStyleLink(nsIConte
   if (NS_FAILED(rv)) {
     // The URI is bad, move along, don't propagate the error (for now)
     return NS_OK;
   }
 
   // If this is a fragment parser, we don't want to observe.
   bool isAlternate;
   rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
-                                 mFragmentMode ? nsnull : this, &isAlternate);
+                                 mRunsToCompletion ? nsnull : this, &isAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
   
-  if (!isAlternate && !mFragmentMode) {
+  if (!isAlternate && !mRunsToCompletion) {
     ++mPendingSheetCount;
     mScriptLoader->AddExecuteBlocker();
   }
 
   return NS_OK;
 }
 
 
@@ -1494,17 +1342,17 @@ nsContentSink::WillResumeImpl()
   mParsing = true;
 
   return NS_OK;
 }
 
 nsresult
 nsContentSink::DidProcessATokenImpl()
 {
-  if (!mCanInterruptParser || !mParser || !mParser->CanInterrupt()) {
+  if (mRunsToCompletion || !mParser) {
     return NS_OK;
   }
 
   // Get the current user event time
   nsIPresShell *shell = mDocument->GetShell();
   if (!shell) {
     // If there's no pres shell in the document, return early since
     // we're not laying anything out here.
@@ -1623,39 +1471,39 @@ nsContentSink::DropParserAndPerfHint(voi
   
   // Ref. Bug 49115
   // Do this hack to make sure that the parser
   // doesn't get destroyed, accidently, before
   // the circularity, between sink & parser, is
   // actually broken.
   // Drop our reference to the parser to get rid of a circular
   // reference.
-  nsCOMPtr<nsIParser> kungFuDeathGrip(mParser.forget());
+  nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
 
   if (mDynamicLowerValue) {
     // Reset the performance hint which was set to FALSE
     // when mDynamicLowerValue was set.
     FavorPerformanceHint(true, 0);
   }
 
-  if (mCanInterruptParser) {
+  if (!mRunsToCompletion) {
     mDocument->UnblockOnload(true);
   }
 }
 
 bool
 nsContentSink::IsScriptExecutingImpl()
 {
   return !!mScriptLoader->GetCurrentScript();
 }
 
 nsresult
 nsContentSink::WillParseImpl(void)
 {
-  if (!mCanInterruptParser) {
+  if (mRunsToCompletion) {
     return NS_OK;
   }
 
   nsIPresShell *shell = mDocument->GetShell();
   if (!shell) {
     return NS_OK;
   }
 
@@ -1684,50 +1532,31 @@ nsContentSink::WillParseImpl(void)
     (mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
 
   return NS_OK;
 }
 
 void
 nsContentSink::WillBuildModelImpl()
 {
-  if (mCanInterruptParser) {
+  if (!mRunsToCompletion) {
     mDocument->BlockOnload();
 
     mBeginLoadTime = PR_IntervalToMicroseconds(PR_IntervalNow());
   }
 
   mDocument->ResetScrolledToRefAlready();
 
   if (mProcessLinkHeaderEvent.get()) {
     mProcessLinkHeaderEvent.Revoke();
 
     DoProcessLinkHeader();
   }
 }
 
-void
-nsContentSink::ContinueInterruptedParsingIfEnabled()
-{
-  // This shouldn't be called in the HTML5 case.
-  if (mParser && mParser->IsParserEnabled()) {
-    mParser->ContinueInterruptedParsing();
-  }
-}
-
-// Overridden in the HTML5 case
-void
-nsContentSink::ContinueInterruptedParsingAsync()
-{
-  nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
-    &nsContentSink::ContinueInterruptedParsingIfEnabled);
-
-  NS_DispatchToCurrentThread(ev);
-}
-
 /* static */
 void
 nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
 {
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (observerService) {
     nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -41,17 +41,16 @@
  */
 
 #ifndef _nsContentSink_h_
 #define _nsContentSink_h_
 
 // Base class for contentsink implementations.
 
 #include "nsICSSLoaderObserver.h"
-#include "nsIScriptLoaderObserver.h"
 #include "nsWeakReference.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsGkAtoms.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
@@ -59,16 +58,17 @@
 #include "nsITimer.h"
 #include "nsStubDocumentObserver.h"
 #include "nsIParserService.h"
 #include "nsIContentSink.h"
 #include "prlog.h"
 #include "nsIRequest.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsThreadUtils.h"
+#include "nsIScriptElement.h"
 
 class nsIDocument;
 class nsIURI;
 class nsIChannel;
 class nsIDocShell;
 class nsIParser;
 class nsIAtom;
 class nsIChannel;
@@ -108,26 +108,23 @@ extern PRLogModuleInfo* gContentSinkLogM
 #undef SINK_NO_INCREMENTAL
 
 //----------------------------------------------------------------------
 
 // 1/2 second fudge factor for window creation
 #define NS_DELAY_FOR_WINDOW_CREATION  500000
 
 class nsContentSink : public nsICSSLoaderObserver,
-                      public nsIScriptLoaderObserver,
                       public nsSupportsWeakReference,
                       public nsStubDocumentObserver,
                       public nsITimerCallback
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink,
-                                           nsIScriptLoaderObserver)
-  NS_DECL_NSISCRIPTLOADEROBSERVER
-
+                                           nsICSSLoaderObserver)
     // nsITimerCallback
   NS_DECL_NSITIMERCALLBACK
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate,
                               nsresult aStatus);
 
   virtual nsresult ProcessMETATag(nsIContent* aContent);
@@ -285,75 +282,70 @@ protected:
   {
     if (mDynamicLowerValue) {
       return 1000;
     }
 
     return sNotificationInterval;
   }
 
-  // Overridable hooks into script evaluation
-  virtual void PreEvaluateScript()                            {return;}
-  virtual void PostEvaluateScript(nsIScriptElement *aElement) {return;}
-
   virtual nsresult FlushTags() = 0;
 
   // Later on we might want to make this more involved somehow
   // (e.g. stop waiting after some timeout or whatnot).
   bool WaitForPendingSheets() { return mPendingSheetCount > 0; }
 
   void DoProcessLinkHeader();
 
+  void StopDeflecting() {
+    mDeflectedCount = sPerfDeflectCount;
+  }
+
 private:
   // People shouldn't be allocating this class directly.  All subclasses should
   // be allocated using a zeroing operator new.
   void* operator new(size_t sz) CPP_THROW_NEW;  // Not to be implemented
 
 protected:
 
-  virtual void ContinueInterruptedParsingAsync();
-  void ContinueInterruptedParsingIfEnabled();
-
   nsCOMPtr<nsIDocument>         mDocument;
-  nsCOMPtr<nsIParser>           mParser;
+  nsRefPtr<nsParserBase>        mParser;
   nsCOMPtr<nsIURI>              mDocumentURI;
   nsCOMPtr<nsIDocShell>         mDocShell;
   nsRefPtr<mozilla::css::Loader> mCSSLoader;
   nsRefPtr<nsNodeInfoManager>   mNodeInfoManager;
   nsRefPtr<nsScriptLoader>      mScriptLoader;
 
-  nsCOMArray<nsIScriptElement> mScriptElements;
-
   // back off timer notification after count
   PRInt32 mBackoffCount;
 
   // Time of last notification
   // Note: mLastNotificationTime is only valid once mLayoutStarted is true.
   PRTime mLastNotificationTime;
 
   // Timer used for notification
   nsCOMPtr<nsITimer> mNotificationTimer;
 
   // Have we already called BeginUpdate for this set of content changes?
   PRUint8 mBeganUpdate : 1;
   PRUint8 mLayoutStarted : 1;
-  PRUint8 mCanInterruptParser : 1;
   PRUint8 mDynamicLowerValue : 1;
   PRUint8 mParsing : 1;
   PRUint8 mDroppedTimer : 1;
   // If true, we deferred starting layout until sheets load
   PRUint8 mDeferredLayoutStart : 1;
   // If true, we deferred notifications until sheets load
   PRUint8 mDeferredFlushTags : 1;
   // If false, we're not ourselves a document observer; that means we
   // shouldn't be performing any more content model notifications,
   // since we're not longer updating our child counts.
   PRUint8 mIsDocumentObserver : 1;
-  // True if this is a fragment parser
-  PRUint8 mFragmentMode : 1;
+  // True if this is parser is a fragment parser or an HTML DOMParser.
+  // XML DOMParser leaves this to false for now!
+  PRUint8 mRunsToCompletion : 1;
   // True to call prevent script execution in the fragment mode.
   PRUint8 mPreventScriptExecution : 1;
   
   //
   // -- Can interrupt parsing members --
   //
 
   // The number of tokens that have been processed since we measured
@@ -401,12 +393,11 @@ protected:
   static PRInt32 sInteractiveParseTime;
   static PRInt32 sPerfParseTime;
   // How long to be in interactive mode after an event
   static PRInt32 sInteractiveTime;
   // How long to stay in perf mode after initial loading
   static PRInt32 sInitialPerfTime;
   // Should we switch between perf-mode and interactive-mode
   static PRInt32 sEnablePerfMode;
-  static bool sCanInterruptParser;
 };
 
 #endif // _nsContentSink_h_
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -274,17 +274,17 @@ nsString* nsContentUtils::sModifierSepar
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sFullScreenKeyInputRestricted = true;
 
 PRUint32 nsContentUtils::sHandlingInputTimeout = 1000;
 
-nsHtml5Parser* nsContentUtils::sHTMLFragmentParser = nsnull;
+nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nsnull;
 nsIParser* nsContentUtils::sXMLFragmentParser = nsnull;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nsnull;
 bool nsContentUtils::sFragmentParsingActive = false;
 
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
@@ -3658,28 +3658,47 @@ nsContentUtils::ParseFragmentHTML(const 
 {
   if (nsContentUtils::sFragmentParsingActive) {
     NS_NOTREACHED("Re-entrant fragment parsing attempted.");
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
   mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
   nsContentUtils::sFragmentParsingActive = true;
   if (!sHTMLFragmentParser) {
-    sHTMLFragmentParser =
-      static_cast<nsHtml5Parser*>(nsHtml5Module::NewHtml5Parser().get());
+    NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
     // Now sHTMLFragmentParser owns the object
   }
   nsresult rv =
-    sHTMLFragmentParser->ParseHtml5Fragment(aSourceBuffer,
-                                            aTargetNode,
-                                            aContextLocalName,
-                                            aContextNamespace,
-                                            aQuirks,
-                                            aPreventScriptExecution);
-  sHTMLFragmentParser->Reset();
+    sHTMLFragmentParser->ParseFragment(aSourceBuffer,
+                                       aTargetNode,
+                                       aContextLocalName,
+                                       aContextNamespace,
+                                       aQuirks,
+                                       aPreventScriptExecution);
+  return rv;
+}
+
+/* static */
+nsresult
+nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer,
+                                  nsIDocument* aTargetDocument)
+{
+  if (nsContentUtils::sFragmentParsingActive) {
+    NS_NOTREACHED("Re-entrant fragment parsing attempted.");
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+  mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
+  nsContentUtils::sFragmentParsingActive = true;
+  if (!sHTMLFragmentParser) {
+    NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
+    // Now sHTMLFragmentParser owns the object
+  }
+  nsresult rv =
+    sHTMLFragmentParser->ParseDocument(aSourceBuffer,
+                                       aTargetDocument);
   return rv;
 }
 
 /* static */
 nsresult
 nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
                                  nsIDocument* aDocument,
                                  nsTArray<nsString>& aTagStack,
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -38,17 +38,16 @@
 #include "jsapi.h"
 #include "nsDOMParser.h"
 #include "nsIURI.h"
 #include "nsIChannel.h"
 #include "nsILoadGroup.h"
 #include "nsIInputStream.h"
 #include "nsNetUtil.h"
 #include "nsStringStream.h"
-#include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsDOMClassInfoID.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsStreamUtils.h"
 #include "nsThreadUtils.h"
@@ -90,23 +89,50 @@ NS_IMPL_RELEASE(nsDOMParser)
 NS_IMETHODIMP 
 nsDOMParser::ParseFromString(const PRUnichar *str, 
                              const char *contentType,
                              nsIDOMDocument **aResult)
 {
   NS_ENSURE_ARG(str);
   NS_ENSURE_ARG_POINTER(aResult);
 
+  nsresult rv;
+
+  if (!nsCRT::strcmp(contentType, "text/html")) {
+    nsCOMPtr<nsIDOMDocument> domDocument;
+    rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument));
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
+    nsDependentString sourceBuffer(str);
+    rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Keep the XULXBL state, base URL and principal setting in sync with the
+    // XML case
+
+    if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
+      document->ForceEnableXULXBL();
+    }
+
+    // Make sure to give this document the right base URI
+    document->SetBaseURI(mBaseURI);
+    // And the right principal
+    document->SetPrincipal(mPrincipal);
+
+    domDocument.forget(aResult);
+    return rv;
+  }
+
   NS_ConvertUTF16toUTF8 data(str);
 
   // The new stream holds a reference to the buffer
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
-                                      data.get(), data.Length(),
-                                      NS_ASSIGNMENT_DEPEND);
+  rv = NS_NewByteInputStream(getter_AddRefs(stream),
+                             data.get(), data.Length(),
+                             NS_ASSIGNMENT_DEPEND);
   if (NS_FAILED(rv))
     return rv;
 
   return ParseFromStream(stream, "UTF-8", data.Length(), contentType, aResult);
 }
 
 NS_IMETHODIMP 
 nsDOMParser::ParseFromBuffer(const PRUint8 *buf,
@@ -147,56 +173,31 @@ nsDOMParser::ParseFromStream(nsIInputStr
   //XXXsmaug Should we create an HTMLDocument (in XHTML mode)
   //         for "application/xhtml+xml"?
   if ((nsCRT::strcmp(contentType, "text/xml") != 0) &&
       (nsCRT::strcmp(contentType, "application/xml") != 0) &&
       (nsCRT::strcmp(contentType, "application/xhtml+xml") != 0) &&
       !svg)
     return NS_ERROR_NOT_IMPLEMENTED;
 
-  nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
-    do_QueryReferent(mScriptHandlingObject);
   nsresult rv;
-  if (!mPrincipal) {
-    NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED);
-    AttemptedInitMarker marker(&mAttemptedInit);
-    
-    nsCOMPtr<nsIPrincipal> prin =
-      do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
-    rv = Init(prin, nsnull, nsnull, scriptHandlingObject);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
 
-  NS_ASSERTION(mPrincipal, "Must have principal by now");
-  NS_ASSERTION(mDocumentURI, "Must have document URI by now");
-  
   // Put the nsCOMPtr out here so we hold a ref to the stream as needed
   nsCOMPtr<nsIInputStream> bufferedStream;
   if (!NS_InputStreamIsBuffered(stream)) {
     rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream,
                                    4096);
     NS_ENSURE_SUCCESS(rv, rv);
 
     stream = bufferedStream;
   }
 
-  // Here we have to cheat a little bit...  Setting the base URI won't
-  // work if the document has a null principal, so use
-  // mOriginalPrincipal when creating the document, then reset the
-  // principal.
   nsCOMPtr<nsIDOMDocument> domDocument;
-  rv = nsContentUtils::CreateDocument(EmptyString(), EmptyString(), nsnull,
-                                      mDocumentURI, mBaseURI,
-                                      mOriginalPrincipal,
-                                      scriptHandlingObject,
-                                      svg ? DocumentFlavorSVG :
-                                            DocumentFlavorLegacyGuess,
-                                      getter_AddRefs(domDocument));
+  rv = SetUpDocument(svg ? DocumentFlavorSVG : DocumentFlavorLegacyGuess,
+                     getter_AddRefs(domDocument));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Create a fake channel 
   nsCOMPtr<nsIChannel> parserChannel;
   NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, nsnull,
                            nsDependentCString(contentType), nsnull);
   NS_ENSURE_STATE(parserChannel);
 
@@ -212,16 +213,19 @@ nsDOMParser::ParseFromStream(nsIInputStr
 
   // Have to pass false for reset here, else the reset will remove
   // our event listener.  Should that listener addition move to later
   // than this call?  Then we wouldn't need to mess around with
   // SetPrincipal, etc, probably!
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   if (!document) return NS_ERROR_FAILURE;
 
+  // Keep the XULXBL state, base URL and principal setting in sync with the
+  // HTML case
+
   if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
     document->ForceEnableXULXBL();
   }
 
   rv = document->StartDocumentLoad(kLoadAsData, parserChannel, 
                                    nsnull, nsnull, 
                                    getter_AddRefs(listener),
                                    false);
@@ -476,8 +480,41 @@ nsDOMParser::Init(nsIPrincipal *aPrincip
 
     // We're called from JS; there better be a subject principal, really.
     NS_ENSURE_TRUE(principal, NS_ERROR_UNEXPECTED);
   }
 
   return Init(principal, aDocumentURI, aBaseURI,
               scriptContext ? scriptContext->GetGlobalObject() : nsnull);
 }
+
+nsresult
+nsDOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
+{
+  nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
+    do_QueryReferent(mScriptHandlingObject);
+  nsresult rv;
+  if (!mPrincipal) {
+    NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED);
+    AttemptedInitMarker marker(&mAttemptedInit);
+
+    nsCOMPtr<nsIPrincipal> prin =
+      do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = Init(prin, nsnull, nsnull, scriptHandlingObject);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  NS_ASSERTION(mPrincipal, "Must have principal by now");
+  NS_ASSERTION(mDocumentURI, "Must have document URI by now");
+
+  // Here we have to cheat a little bit...  Setting the base URI won't
+  // work if the document has a null principal, so use
+  // mOriginalPrincipal when creating the document, then reset the
+  // principal.
+  return nsContentUtils::CreateDocument(EmptyString(), EmptyString(), nsnull,
+                                        mDocumentURI, mBaseURI,
+                                        mOriginalPrincipal,
+                                        scriptHandlingObject,
+                                        aFlavor,
+                                        aResult);
+}
--- a/content/base/src/nsDOMParser.h
+++ b/content/base/src/nsDOMParser.h
@@ -38,16 +38,17 @@
 #ifndef nsDOMParser_h__
 #define nsDOMParser_h__
 
 #include "nsIDOMParser.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsWeakReference.h"
 #include "nsIJSNativeInitializer.h"
+#include "nsIDocument.h"
 
 class nsDOMParser : public nsIDOMParser,
                     public nsIDOMParserJS,
                     public nsIJSNativeInitializer,
                     public nsSupportsWeakReference
 {
 public: 
   nsDOMParser();
@@ -61,16 +62,18 @@ public:
   // nsIDOMParserJS
   NS_DECL_NSIDOMPARSERJS
 
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
                         PRUint32 argc, jsval *argv);
 
 private:
+  nsresult SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult);
+
   class AttemptedInitMarker {
   public:
     AttemptedInitMarker(bool* aAttemptedInit) :
       mAttemptedInit(aAttemptedInit)
     {}
 
     ~AttemptedInitMarker() {
       *mAttemptedInit = true;
--- a/content/base/src/nsPlainTextSerializer.h
+++ b/content/base/src/nsPlainTextSerializer.h
@@ -99,17 +99,17 @@ public:
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
   // nsIContentSink
   NS_IMETHOD WillParse(void) { return NS_OK; }
   NS_IMETHOD WillInterrupt(void) { return NS_OK; }
   NS_IMETHOD WillResume(void) { return NS_OK; }
-  NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
   NS_IMETHOD AddComment(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode) { return NS_OK; }
   virtual void FlushPendingNotifications(mozFlushType aType) { }
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -937,18 +937,19 @@ nsScriptLoader::ProcessPendingRequestsAs
 void
 nsScriptLoader::ProcessPendingRequests()
 {
   nsRefPtr<nsScriptLoadRequest> request;
   if (mParserBlockingRequest &&
       !mParserBlockingRequest->mLoading &&
       ReadyToExecuteScripts()) {
     request.swap(mParserBlockingRequest);
-    // nsContentSink::ScriptAvailable unblocks the parser
+    UnblockParser(request);
     ProcessRequest(request);
+    ContinueParserAsync(request);
   }
 
   while (ReadyToExecuteScripts() && 
          !mXSLTRequests.IsEmpty() && 
          !mXSLTRequests[0]->mLoading) {
     request.swap(mXSLTRequests[0]);
     mXSLTRequests.RemoveElementAt(0);
     ProcessRequest(request);
@@ -1164,29 +1165,42 @@ nsScriptLoader::OnStreamComplete(nsIStre
   if (NS_FAILED(rv)) {
     if (mDeferRequests.RemoveElement(request) ||
         mAsyncRequests.RemoveElement(request) ||
         mNonAsyncExternalScriptInsertedRequests.RemoveElement(request) ||
         mXSLTRequests.RemoveElement(request)) {
       FireScriptAvailable(rv, request);
     } else if (mParserBlockingRequest == request) {
       mParserBlockingRequest = nsnull;
-      // nsContentSink::ScriptAvailable unblocks the parser
+      UnblockParser(request);
       FireScriptAvailable(rv, request);
+      ContinueParserAsync(request);
     } else {
       mPreloads.RemoveElement(request, PreloadRequestComparator());
     }
   }
 
   // Process our request and/or any pending ones
   ProcessPendingRequests();
 
   return NS_OK;
 }
 
+void
+nsScriptLoader::UnblockParser(nsScriptLoadRequest* aParserBlockingRequest)
+{
+  aParserBlockingRequest->mElement->UnblockParser();
+}
+
+void
+nsScriptLoader::ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest)
+{
+  aParserBlockingRequest->mElement->ContinueParserAsync();
+}
+
 nsresult
 nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
                                      nsIStreamLoader* aLoader,
                                      nsresult aStatus,
                                      PRUint32 aStringLen,
                                      const PRUint8* aString)
 {
   if (NS_FAILED(aStatus)) {
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -239,16 +239,27 @@ public:
    * @param aCharset The charset parameter for the script.
    * @param aType The type parameter for the script.
    */
   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
                           const nsAString &aType);
 
 private:
   /**
+   * Unblocks the creator parser of the parser-blocking scripts.
+   */
+  void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
+
+  /**
+   * Asynchronously resumes the creator parser of the parser-blocking scripts.
+   */
+  void ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest);
+
+
+  /**
    * Helper function to check the content policy for a given request.
    */
   static nsresult CheckContentPolicy(nsIDocument* aDocument,
                                      nsISupports *aContext,
                                      nsIURI *aURI,
                                      const nsAString &aType);
 
   /**
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -52,16 +52,17 @@ EXPORTS		= \
 		nsClientRect.h \
 		nsHTMLDNSPrefetch.h \
 		$(NULL)
 
 CPPSRCS		= \
 		nsClientRect.cpp \
 		nsHTMLDNSPrefetch.cpp \
 		nsGenericHTMLElement.cpp \
+		nsGenericHTMLFrameElement.cpp \
 		nsFormSubmission.cpp \
 		nsTextEditorState.cpp \
 		nsHTMLElement.cpp \
 		nsHTMLAnchorElement.cpp \
 		nsHTMLAreaElement.cpp \
 		nsHTMLBRElement.cpp \
 		nsHTMLBodyElement.cpp \
 		nsHTMLButtonElement.cpp \
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2547,19 +2547,16 @@ nsGenericHTMLElement::GetContextMenu(nsI
     element.forget(aContextMenu);
   }
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 
-NS_IMPL_INT_ATTR(nsGenericHTMLFrameElement, TabIndex, tabindex)
-NS_IMPL_BOOL_ATTR(nsGenericHTMLFrameElement, MozBrowser, mozbrowser)
-
 nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
   , mForm(nsnull)
   , mFieldSet(nsnull)
 {
   // We should add the NS_EVENT_STATE_ENABLED bit here as needed, but
   // that depends on our type, which is not initialized yet.  So we
   // have to do this in subclasses.
@@ -2660,34 +2657,16 @@ nsGenericHTMLFormElement::GetDesiredIMES
     return nsGenericHTMLElement::GetDesiredIMEState();
   IMEState state;
   rv = imeEditor->GetPreferredIMEState(&state);
   if (NS_FAILED(rv))
     return nsGenericHTMLElement::GetDesiredIMEState();
   return state;
 }
 
-bool
-nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
-                                           bool *aIsFocusable,
-                                           PRInt32 *aTabIndex)
-{
-  if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
-    return true;
-  }
-
-  *aIsFocusable = nsContentUtils::IsSubDocumentTabbable(this);
-
-  if (!*aIsFocusable && aTabIndex) {
-    *aTabIndex = -1;
-  }
-
-  return false;
-}
-
 nsresult
 nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
                                      nsIContent* aParent,
                                      nsIContent* aBindingParent,
                                      bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
@@ -3203,343 +3182,16 @@ nsGenericHTMLFormElement::UpdateFieldSet
 void
 nsGenericHTMLFormElement::FieldSetDisabledChanged(bool aNotify)
 {
   UpdateState(aNotify);
 }
 
 //----------------------------------------------------------------------
 
-nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
-{
-  if (mFrameLoader) {
-    mFrameLoader->Destroy();
-  }
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
-                                                  nsGenericHTMLElement)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFrameLoader, nsIFrameLoader)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_INTERFACE_TABLE_HEAD(nsGenericHTMLFrameElement)
-  NS_INTERFACE_TABLE_INHERITED2(nsGenericHTMLFrameElement,
-                                nsIFrameLoaderOwner,
-                                nsIDOMMozBrowserFrameElement)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLFrameElement)
-NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
-
-nsresult
-nsGenericHTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
-{
-  NS_PRECONDITION(aContentDocument, "Null out param");
-  *aContentDocument = nsnull;
-
-  nsCOMPtr<nsIDOMWindow> win;
-  GetContentWindow(getter_AddRefs(win));
-
-  if (!win) {
-    return NS_OK;
-  }
-
-  return win->GetDocument(aContentDocument);
-}
-
-nsresult
-nsGenericHTMLFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
-{
-  NS_PRECONDITION(aContentWindow, "Null out param");
-  *aContentWindow = nsnull;
-
-  nsresult rv = EnsureFrameLoader();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!mFrameLoader) {
-    return NS_OK;
-  }
-
-  bool depthTooGreat = false;
-  mFrameLoader->GetDepthTooGreat(&depthTooGreat);
-  if (depthTooGreat) {
-    // Claim to have no contentWindow
-    return NS_OK;
-  }
-  
-  nsCOMPtr<nsIDocShell> doc_shell;
-  mFrameLoader->GetDocShell(getter_AddRefs(doc_shell));
-
-  nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(doc_shell));
-
-  if (!win) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(win->IsOuterWindow(),
-               "Uh, this window should always be an outer window!");
-
-  return CallQueryInterface(win, aContentWindow);
-}
-
-nsresult
-nsGenericHTMLFrameElement::EnsureFrameLoader()
-{
-  if (!GetParent() || !IsInDoc() || mFrameLoader) {
-    // If frame loader is there, we just keep it around, cached
-    return NS_OK;
-  }
-
-  mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
-{
-  NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
-  return NS_OK;
-}
-
-NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
-nsGenericHTMLFrameElement::GetFrameLoader()
-{
-  nsRefPtr<nsFrameLoader> loader = mFrameLoader;
-  return loader.forget();
-}
-
-NS_IMETHODIMP
-nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
-{
-  // We don't support this yet
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-nsresult
-nsGenericHTMLFrameElement::LoadSrc()
-{
-  nsresult rv = EnsureFrameLoader();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!mFrameLoader) {
-    return NS_OK;
-  }
-
-  rv = mFrameLoader->LoadFrame();
-#ifdef DEBUG
-  if (NS_FAILED(rv)) {
-    NS_WARNING("failed to load URL");
-  }
-#endif
-
-  return rv;
-}
-
-nsresult
-nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument,
-                                      nsIContent* aParent,
-                                      nsIContent* aBindingParent,
-                                      bool aCompileEventHandlers)
-{
-  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
-                                                 aBindingParent,
-                                                 aCompileEventHandlers);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aDocument) {
-    NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
-                 "Missing a script blocker!");
-    // We're in a document now.  Kick off the frame load.
-    LoadSrc();
-  }
-
-  // We're now in document and scripts may move us, so clear
-  // the mNetworkCreated flag.
-  mNetworkCreated = false;
-  return rv;
-}
-
-void
-nsGenericHTMLFrameElement::UnbindFromTree(bool aDeep, bool aNullParent)
-{
-  if (mFrameLoader) {
-    // This iframe is being taken out of the document, destroy the
-    // iframe's frame loader (doing that will tear down the window in
-    // this iframe).
-    // XXXbz we really want to only partially destroy the frame
-    // loader... we don't want to tear down the docshell.  Food for
-    // later bug.
-    mFrameLoader->Destroy();
-    mFrameLoader = nsnull;
-  }
-
-  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-}
-
-nsresult
-nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                   nsIAtom* aPrefix, const nsAString& aValue,
-                                   bool aNotify)
-{
-  nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
-                                              aValue, aNotify);
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
-    // Don't propagate error here. The attribute was successfully set, that's
-    // what we should reflect.
-    LoadSrc();
-  }
-
-  return NS_OK;
-}
-
-void
-nsGenericHTMLFrameElement::DestroyContent()
-{
-  if (mFrameLoader) {
-    mFrameLoader->Destroy();
-    mFrameLoader = nsnull;
-  }
-
-  nsGenericHTMLElement::DestroyContent();
-}
-
-nsresult
-nsGenericHTMLFrameElement::CopyInnerTo(nsGenericElement* aDest) const
-{
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsIDocument* doc = aDest->OwnerDoc();
-  if (doc->IsStaticDocument() && mFrameLoader) {
-    nsGenericHTMLFrameElement* dest =
-      static_cast<nsGenericHTMLFrameElement*>(aDest);
-    nsFrameLoader* fl = nsFrameLoader::Create(dest, false);
-    NS_ENSURE_STATE(fl);
-    dest->mFrameLoader = fl;
-    static_cast<nsFrameLoader*>(mFrameLoader.get())->CreateStaticClone(fl);
-  }
-
-  return rv;
-}
-
-PRInt64
-nsGenericHTMLFrameElement::SizeOf() const
-{
-  PRInt64 size = MemoryReporter::GetBasicSize<nsGenericHTMLFrameElement,
-                                              nsGenericHTMLElement>(this);
-  // TODO: need to implement SizeOf() in nsFrameLoader, bug 672539.
-  size += mFrameLoader ? sizeof(*mFrameLoader.get()) : 0;
-  return size;
-}
-
-namespace {
-
-// GetContentStateCallbackRunnable is used by MozGetContentState to fire its callback
-// asynchronously.
-class GetContentStateCallbackRunnable : public nsRunnable
-{
-public:
-  GetContentStateCallbackRunnable(nsIDOMMozGetContentStateCallback *aCallback,
-                             nsIDOMEventTarget *aEventTarget,
-                             const nsAString &aResult)
-    : mCallback(aCallback)
-    , mEventTarget(aEventTarget)
-    , mResult(aResult)
-  {
-  }
-
-  NS_IMETHOD Run()
-  {
-    FireCallback();
-
-    // Break cycles.
-    mCallback = NULL;
-    mEventTarget = NULL;
-    return NS_OK;
-  }
-
-private:
-  void FireCallback()
-  {
-    nsCxPusher pusher;
-    if (!pusher.Push(mEventTarget)) {
-      return;
-    }
-
-    mCallback->Callback(mResult);
-  }
-
-  nsCOMPtr<nsIDOMMozGetContentStateCallback> mCallback;
-  nsCOMPtr<nsIDOMEventTarget> mEventTarget;
-  const nsString mResult;
-};
-
-} // anonymous namespace
-
-nsresult
-nsGenericHTMLFrameElement::BrowserFrameSecurityCheck()
-{
-  if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) {
-    return NS_ERROR_FAILURE;
-  }
-
-  bool browser;
-  GetMozBrowser(&browser);
-  if (!browser) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsIPrincipal *principal = NodePrincipal();
-  nsCOMPtr<nsIURI> principalURI;
-  principal->GetURI(getter_AddRefs(principalURI));
-  if (!nsContentUtils::URIIsChromeOrInPref(principalURI,
-                                           "dom.mozBrowserFramesWhitelist")) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsGenericHTMLFrameElement::MozGetContentState(const nsAString &aProperty,
-                                              nsIDOMMozGetContentStateCallback *aCallback)
-{
-  nsresult rv = BrowserFrameSecurityCheck();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!aProperty.EqualsLiteral("location")) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIDOMWindow> contentWindow;
-  GetContentWindow(getter_AddRefs(contentWindow));
-  NS_ENSURE_TRUE(contentWindow, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDOMLocation> location;
-  rv = contentWindow->GetLocation(getter_AddRefs(location));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoString href;
-  rv = location->ToString(href);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMEventTarget> eventTarget =
-    do_QueryInterface(nsContentUtils::GetWindowFromCaller());
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_FAILURE);
-
-  // Asynchronously fire the callback.
-  nsRefPtr<GetContentStateCallbackRunnable> runnable =
-    new GetContentStateCallbackRunnable(aCallback, eventTarget, href);
-  NS_DispatchToMainThread(runnable);
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-
 nsresult
 nsGenericHTMLElement::Blur()
 {
   if (!ShouldBlur(this)) {
     return NS_OK;
   }
 
   nsIDocument* doc = GetCurrentDoc();
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -37,22 +37,20 @@
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsGenericHTMLElement_h___
 #define nsGenericHTMLElement_h___
 
 #include "nsMappedAttributeElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsINameSpaceManager.h"  // for kNameSpaceID_None
 #include "nsIFormControl.h"
-#include "nsIDOMHTMLFrameElement.h"
 #include "nsFrameLoader.h"
 #include "nsGkAtoms.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsDOMMemoryReporter.h"
-#include "nsIDOMMozBrowserFrameElement.h"
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIDOMNodeList;
 class nsIFrame;
 class nsIStyleRule;
 class nsChildContentList;
 class nsDOMCSSDeclaration;
@@ -1011,89 +1009,16 @@ protected:
 // same bit.  --bz
 
 // Make sure we have enough space for those bits
 PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
 
 //----------------------------------------------------------------------
 
 /**
- * A helper class for frame elements
- */
-
-class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
-                                  public nsIFrameLoaderOwner,
-                                  public nsIDOMMozBrowserFrameElement
-{
-public:
-  nsGenericHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
-                            mozilla::dom::FromParser aFromParser)
-    : nsGenericHTMLElement(aNodeInfo)
-  {
-    mNetworkCreated = aFromParser == mozilla::dom::FROM_PARSER_NETWORK;
-  }
-  virtual ~nsGenericHTMLFrameElement();
-
-  NS_DECL_DOM_MEMORY_REPORTER_SIZEOF
-
-  // nsISupports
-  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
-
-  // nsIFrameLoaderOwner
-  NS_DECL_NSIFRAMELOADEROWNER
-
-  // nsIContent
-  virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex);
-  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
-                              nsIContent* aBindingParent,
-                              bool aCompileEventHandlers);
-  virtual void UnbindFromTree(bool aDeep = true,
-                              bool aNullParent = true);
-  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                   const nsAString& aValue, bool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
-  }
-  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                           nsIAtom* aPrefix, const nsAString& aValue,
-                           bool aNotify);
-  virtual void DestroyContent();
-
-  nsresult CopyInnerTo(nsGenericElement* aDest) const;
-
-  // nsIDOMHTMLElement 
-  NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex);
-  NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
-                                                     nsGenericHTMLElement)
-
-  // nsIDOMMozBrowserFrameElement
-  NS_DECL_NSIDOMMOZBROWSERFRAMEELEMENT
-
-protected:
-  // This doesn't really ensure a frame loade in all cases, only when
-  // it makes sense.
-  nsresult EnsureFrameLoader();
-  nsresult LoadSrc();
-  nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
-  nsresult GetContentWindow(nsIDOMWindow** aContentWindow);
-
-  nsresult BrowserFrameSecurityCheck();
-
-  nsRefPtr<nsFrameLoader> mFrameLoader;
-  // True when the element is created by the parser
-  // using NS_FROM_PARSER_NETWORK flag.
-  // If the element is modified, it may lose the flag.
-  bool                    mNetworkCreated;
-};
-
-//----------------------------------------------------------------------
-
-/**
  * A macro to implement the getter and setter for a given string
  * valued content property. The method uses the generic GetAttr and
  * SetAttr methods.
  */
 #define NS_IMPL_STRING_ATTR(_class, _method, _atom)                  \
   NS_IMETHODIMP                                                      \
   _class::Get##_method(nsAString& aValue)                            \
   {                                                                  \
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -0,0 +1,446 @@
+/* -*- 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 "nsGenericHTMLFrameElement.h"
+#include "nsIWebProgress.h"
+#include "nsIPrivateDOMEvent.h"
+#include "nsIDOMCustomEvent.h"
+#include "nsIVariant.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsVariant.h"
+#include "nsContentUtils.h"
+#include "nsDOMMemoryReporter.h"
+#include "nsEventDispatcher.h"
+#include "nsContentUtils.h"
+#include "nsAsyncDOMEvent.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
+                                                  nsGenericHTMLElement)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFrameLoader, nsIFrameLoader)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_TABLE_HEAD(nsGenericHTMLFrameElement)
+  NS_INTERFACE_TABLE_INHERITED3(nsGenericHTMLFrameElement,
+                                nsIFrameLoaderOwner,
+                                nsIDOMMozBrowserFrame,
+                                nsIWebProgressListener)
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLFrameElement)
+NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
+
+NS_IMPL_INT_ATTR(nsGenericHTMLFrameElement, TabIndex, tabindex)
+NS_IMPL_BOOL_ATTR(nsGenericHTMLFrameElement, Mozbrowser, mozbrowser)
+
+nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
+{
+  if (mFrameLoader) {
+    mFrameLoader->Destroy();
+  }
+}
+
+nsresult
+nsGenericHTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
+{
+  NS_PRECONDITION(aContentDocument, "Null out param");
+  *aContentDocument = nsnull;
+
+  nsCOMPtr<nsIDOMWindow> win;
+  GetContentWindow(getter_AddRefs(win));
+
+  if (!win) {
+    return NS_OK;
+  }
+
+  return win->GetDocument(aContentDocument);
+}
+
+nsresult
+nsGenericHTMLFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
+{
+  NS_PRECONDITION(aContentWindow, "Null out param");
+  *aContentWindow = nsnull;
+
+  nsresult rv = EnsureFrameLoader();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!mFrameLoader) {
+    return NS_OK;
+  }
+
+  bool depthTooGreat = false;
+  mFrameLoader->GetDepthTooGreat(&depthTooGreat);
+  if (depthTooGreat) {
+    // Claim to have no contentWindow
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDocShell> doc_shell;
+  mFrameLoader->GetDocShell(getter_AddRefs(doc_shell));
+
+  nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(doc_shell));
+
+  if (!win) {
+    return NS_OK;
+  }
+
+  NS_ASSERTION(win->IsOuterWindow(),
+               "Uh, this window should always be an outer window!");
+
+  return CallQueryInterface(win, aContentWindow);
+}
+
+nsresult
+nsGenericHTMLFrameElement::EnsureFrameLoader()
+{
+  if (!GetParent() || !IsInDoc() || mFrameLoader) {
+    // If frame loader is there, we just keep it around, cached
+    return NS_OK;
+  }
+
+  mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
+  if (!mFrameLoader) {
+    // Strangely enough, this method doesn't actually ensure that the
+    // frameloader exists.  It's more of a best-effort kind of thing.
+    return NS_OK;
+  }
+
+  // Register ourselves as a web progress listener on the frameloader's
+  // docshell.
+  nsCOMPtr<nsIDocShell> docShell;
+  mFrameLoader->GetDocShell(getter_AddRefs(docShell));
+  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
+  NS_ENSURE_TRUE(webProgress, NS_OK);
+
+  // This adds a weak ref, so we don't have to worry about unregistering.
+  webProgress->AddProgressListener(this,
+    nsIWebProgress::NOTIFY_LOCATION |
+    nsIWebProgress::NOTIFY_STATE_WINDOW);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
+{
+  NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
+nsGenericHTMLFrameElement::GetFrameLoader()
+{
+  nsRefPtr<nsFrameLoader> loader = mFrameLoader;
+  return loader.forget();
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
+{
+  // We don't support this yet
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+nsGenericHTMLFrameElement::LoadSrc()
+{
+  nsresult rv = EnsureFrameLoader();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!mFrameLoader) {
+    return NS_OK;
+  }
+
+  rv = mFrameLoader->LoadFrame();
+#ifdef DEBUG
+  if (NS_FAILED(rv)) {
+    NS_WARNING("failed to load URL");
+  }
+#endif
+
+  return rv;
+}
+
+nsresult
+nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument,
+                                      nsIContent* aParent,
+                                      nsIContent* aBindingParent,
+                                      bool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
+                                                 aBindingParent,
+                                                 aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aDocument) {
+    NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
+                 "Missing a script blocker!");
+    // We're in a document now.  Kick off the frame load.
+    LoadSrc();
+  }
+
+  // We're now in document and scripts may move us, so clear
+  // the mNetworkCreated flag.
+  mNetworkCreated = false;
+  return rv;
+}
+
+void
+nsGenericHTMLFrameElement::UnbindFromTree(bool aDeep, bool aNullParent)
+{
+  if (mFrameLoader) {
+    // This iframe is being taken out of the document, destroy the
+    // iframe's frame loader (doing that will tear down the window in
+    // this iframe).
+    // XXXbz we really want to only partially destroy the frame
+    // loader... we don't want to tear down the docshell.  Food for
+    // later bug.
+    mFrameLoader->Destroy();
+    mFrameLoader = nsnull;
+  }
+
+  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
+}
+
+nsresult
+nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                                   nsIAtom* aPrefix, const nsAString& aValue,
+                                   bool aNotify)
+{
+  nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
+                                              aValue, aNotify);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
+    // Don't propagate error here. The attribute was successfully set, that's
+    // what we should reflect.
+    LoadSrc();
+  }
+
+  return NS_OK;
+}
+
+void
+nsGenericHTMLFrameElement::DestroyContent()
+{
+  if (mFrameLoader) {
+    mFrameLoader->Destroy();
+    mFrameLoader = nsnull;
+  }
+
+  nsGenericHTMLElement::DestroyContent();
+}
+
+nsresult
+nsGenericHTMLFrameElement::CopyInnerTo(nsGenericElement* aDest) const
+{
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsIDocument* doc = aDest->OwnerDoc();
+  if (doc->IsStaticDocument() && mFrameLoader) {
+    nsGenericHTMLFrameElement* dest =
+      static_cast<nsGenericHTMLFrameElement*>(aDest);
+    nsFrameLoader* fl = nsFrameLoader::Create(dest, false);
+    NS_ENSURE_STATE(fl);
+    dest->mFrameLoader = fl;
+    static_cast<nsFrameLoader*>(mFrameLoader.get())->CreateStaticClone(fl);
+  }
+
+  return rv;
+}
+
+bool
+nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
+                                           bool *aIsFocusable,
+                                           PRInt32 *aTabIndex)
+{
+  if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
+    return true;
+  }
+
+  *aIsFocusable = nsContentUtils::IsSubDocumentTabbable(this);
+
+  if (!*aIsFocusable && aTabIndex) {
+    *aTabIndex = -1;
+  }
+
+  return false;
+}
+
+PRInt64
+nsGenericHTMLFrameElement::SizeOf() const
+{
+  PRInt64 size = MemoryReporter::GetBasicSize<nsGenericHTMLFrameElement,
+                                              nsGenericHTMLElement>(this);
+  // TODO: need to implement SizeOf() in nsFrameLoader, bug 672539.
+  size += mFrameLoader ? sizeof(*mFrameLoader.get()) : 0;
+  return size;
+}
+
+/**
+ * Return true if this frame element has permission to send mozbrowser
+ * events, and false otherwise.
+ */
+bool
+nsGenericHTMLFrameElement::BrowserFrameSecurityCheck()
+{
+  // Fail if browser frames are globally disabled.
+  if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) {
+    return false;
+  }
+
+  // Fail if this frame doesn't have the mozbrowser attribute.
+  bool isBrowser = false;
+  GetMozbrowser(&isBrowser);
+  if (!isBrowser) {
+    return false;
+  }
+
+  // Fail if the node principal isn't trusted.
+  nsIPrincipal *principal = NodePrincipal();
+  nsCOMPtr<nsIURI> principalURI;
+  principal->GetURI(getter_AddRefs(principalURI));
+  if (!nsContentUtils::URIIsChromeOrInPref(principalURI,
+                                           "dom.mozBrowserFramesWhitelist")) {
+    return false;
+  }
+
+  // Otherwise, succeed.
+  return true;
+}
+
+/**
+ * Fire a mozbrowser event, if we have permission.
+ *
+ * @param aEventName the event name (e.g. "locationchange").  "mozbrowser" is
+ *        added to the beginning of aEventName automatically.
+ * @param aEventType the event type.  Must be either "event" or "customevent".
+ * @param aValue the value passed along with the event.  This value will be
+ *        set as the event's "detail" property.  This must be empty if
+ *        aEventType is "event".
+ */
+nsresult
+nsGenericHTMLFrameElement::MaybeFireBrowserEvent(
+  const nsAString &aEventName,
+  const nsAString &aEventType,
+  const nsAString &aValue /* = EmptyString() */)
+{
+  MOZ_ASSERT(aEventType.EqualsLiteral("event") ||
+             aEventType.EqualsLiteral("customevent"));
+  MOZ_ASSERT_IF(aEventType.EqualsLiteral("event"),
+                aValue.IsEmpty());
+
+  if (!BrowserFrameSecurityCheck()) {
+    return NS_OK;
+  }
+
+  nsAutoString eventName;
+  eventName.AppendLiteral("mozbrowser");
+  eventName.Append(aEventName);
+
+  nsCOMPtr<nsIDOMEvent> domEvent;
+  nsEventDispatcher::CreateEvent(GetPresContext(), nsnull,
+                                 aEventType, getter_AddRefs(domEvent));
+
+  nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
+  NS_ENSURE_STATE(privateEvent);
+
+  nsresult rv = privateEvent->SetTrusted(true);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aEventType.EqualsLiteral("customevent")) {
+    nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent);
+    NS_ENSURE_STATE(customEvent);
+
+    nsCOMPtr<nsIWritableVariant> value = new nsVariant();
+    value->SetAsAString(aValue);
+
+    rv = customEvent->InitCustomEvent(eventName,
+                                      /* bubbles = */ false,
+                                      /* cancelable = */ false,
+                                      value);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  else {
+    rv = domEvent->InitEvent(eventName,
+                             /* bubbles = */ false,
+                             /* cancelable = */ false);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return (new nsAsyncDOMEvent(this, domEvent))->PostDOMEvent();
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnLocationChange(nsIWebProgress* aWebProgress,
+                                            nsIRequest* aRequest,
+                                            nsIURI* aURI,
+                                            PRUint32 aFlags)
+{
+  nsCAutoString spec;
+  aURI->GetSpec(spec);
+
+  MaybeFireBrowserEvent(NS_LITERAL_STRING("locationchange"),
+                        NS_LITERAL_STRING("customevent"),
+                        NS_ConvertUTF8toUTF16(spec));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnStateChange(nsIWebProgress* aProgress,
+                                         nsIRequest* aRequest,
+                                         PRUint32 aProgressStateFlags,
+                                         nsresult aStatus)
+{
+  if (!(aProgressStateFlags & STATE_IS_WINDOW)) {
+    return NS_OK;
+  }
+
+  nsAutoString status;
+  if (aProgressStateFlags & STATE_START) {
+    MaybeFireBrowserEvent(NS_LITERAL_STRING("loadstart"),
+                          NS_LITERAL_STRING("event"));
+  }
+  else if (aProgressStateFlags & STATE_STOP) {
+    MaybeFireBrowserEvent(NS_LITERAL_STRING("loadend"),
+                          NS_LITERAL_STRING("event"));
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnProgressChange(nsIWebProgress* aProgress,
+                                            nsIRequest* aRequest,
+                                            PRInt32 aCurSelfProgress,
+                                            PRInt32 aMaxSelfProgress,
+                                            PRInt32 aCurTotalProgress,
+                                            PRInt32 aMaxTotalProgress)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnStatusChange(nsIWebProgress* aWebProgress,
+                                          nsIRequest* aRequest,
+                                          nsresult aStatus,
+                                          const PRUnichar* aMessage)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnSecurityChange(nsIWebProgress *aWebProgress,
+                                            nsIRequest *aRequest,
+                                            PRUint32 state)
+{
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsGenericHTMLFrameElement.h
@@ -0,0 +1,80 @@
+/* -*- 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 "nsGenericHTMLElement.h"
+#include "nsIDOMHTMLFrameElement.h"
+#include "nsIDOMMozBrowserFrame.h"
+#include "nsIWebProgressListener.h"
+
+/**
+ * A helper class for frame elements
+ */
+class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
+                                  public nsIFrameLoaderOwner,
+                                  public nsIDOMMozBrowserFrame,
+                                  public nsIWebProgressListener
+{
+public:
+  nsGenericHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                            mozilla::dom::FromParser aFromParser)
+    : nsGenericHTMLElement(aNodeInfo)
+  {
+    mNetworkCreated = aFromParser == mozilla::dom::FROM_PARSER_NETWORK;
+  }
+  virtual ~nsGenericHTMLFrameElement();
+
+  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
+  NS_DECL_NSIFRAMELOADEROWNER
+  NS_DECL_NSIDOMMOZBROWSERFRAME
+  NS_DECL_NSIWEBPROGRESSLISTENER
+  NS_DECL_DOM_MEMORY_REPORTER_SIZEOF
+
+  // nsIContent
+  virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex);
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              bool aCompileEventHandlers);
+  virtual void UnbindFromTree(bool aDeep = true,
+                              bool aNullParent = true);
+  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                   const nsAString& aValue, bool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
+  }
+  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                           nsIAtom* aPrefix, const nsAString& aValue,
+                           bool aNotify);
+  virtual void DestroyContent();
+
+  nsresult CopyInnerTo(nsGenericElement* aDest) const;
+
+  // nsIDOMHTMLElement
+  NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex);
+  NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
+                                                     nsGenericHTMLElement)
+
+protected:
+  // This doesn't really ensure a frame loade in all cases, only when
+  // it makes sense.
+  nsresult EnsureFrameLoader();
+  nsresult LoadSrc();
+  nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
+  nsresult GetContentWindow(nsIDOMWindow** aContentWindow);
+
+  bool BrowserFrameSecurityCheck();
+  nsresult MaybeFireBrowserEvent(const nsAString &aEventName,
+                                 const nsAString &aEventType,
+                                 const nsAString &aValue = EmptyString());
+
+  nsRefPtr<nsFrameLoader> mFrameLoader;
+  // True when the element is created by the parser
+  // using NS_FROM_PARSER_NETWORK flag.
+  // If the element is modified, it may lose the flag.
+  bool                    mNetworkCreated;
+};
--- a/content/html/content/src/nsHTMLFrameElement.cpp
+++ b/content/html/content/src/nsHTMLFrameElement.cpp
@@ -33,17 +33,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLFrameElement.h"
-#include "nsGenericHTMLElement.h"
+#include "nsGenericHTMLFrameElement.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsDOMError.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/nsHTMLIFrameElement.cpp
@@ -33,17 +33,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/Util.h"
 
 #include "nsIDOMHTMLIFrameElement.h"
-#include "nsGenericHTMLElement.h"
+#include "nsGenericHTMLFrameElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMGetSVGDocument.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsMappedAttributes.h"
 #include "nsDOMError.h"
 #include "nsRuleData.h"
--- a/content/html/content/test/test_bug389797.html
+++ b/content/html/content/test/test_bug389797.html
@@ -138,31 +138,31 @@ HTML_TAG("dt", "");
 HTML_TAG("em", "");
 HTML_TAG("embed", "Embed", [ "nsIDOMGetSVGDocument" ], objectIfaces);
 HTML_TAG("fieldset", "FieldSet");
 HTML_TAG("figcaption", "")
 HTML_TAG("figure", "")
 HTML_TAG("font", "Font");
 HTML_TAG("footer", "")
 HTML_TAG("form", "Form", [], [ "nsIWebProgressListener" ]);
-HTML_TAG("frame", "Frame", [ "nsIDOMMozBrowserFrameElement" ], [ "nsIFrameLoaderOwner" ]);
+HTML_TAG("frame", "Frame", [ "nsIDOMMozBrowserFrame" ], [ "nsIFrameLoaderOwner" ]);
 HTML_TAG("frameset", "FrameSet");
 HTML_TAG("h1", "Heading");
 HTML_TAG("h2", "Heading");
 HTML_TAG("h3", "Heading");
 HTML_TAG("h4", "Heading");
 HTML_TAG("h5", "Heading");
 HTML_TAG("h6", "Heading");
 HTML_TAG("head", "Head");
 HTML_TAG("header", "")
 HTML_TAG("hgroup", "")
 HTML_TAG("hr", "HR");
 HTML_TAG("html", "Html");
 HTML_TAG("i", "");
-HTML_TAG("iframe", "IFrame", [ "nsIDOMGetSVGDocument", "nsIDOMMozBrowserFrameElement" ],
+HTML_TAG("iframe", "IFrame", [ "nsIDOMGetSVGDocument", "nsIDOMMozBrowserFrame" ],
                              [ "nsIFrameLoaderOwner" ]);
 HTML_TAG("image", "Span");
 HTML_TAG("img", "Image", [], [ "imgIDecoderObserver",
                                "nsIImageLoadingContent" ]);
 HTML_TAG("input", "Input", [], [ "imgIDecoderObserver",
                                  "nsIImageLoadingContent",
                                  "nsIDOMNSEditableElement" ]);
 HTML_TAG("ins", "Mod");
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -186,17 +186,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink, nsContentSink)
 
   // nsIContentSink
   NS_IMETHOD WillParse(void);
   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   NS_IMETHOD DidBuildModel(bool aTerminated);
   NS_IMETHOD WillInterrupt(void);
   NS_IMETHOD WillResume(void);
-  NS_IMETHOD SetParser(nsIParser* aParser);
+  NS_IMETHOD SetParser(nsParserBase* aParser);
   virtual void FlushPendingNotifications(mozFlushType aType);
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
   virtual nsISupports *GetTarget();
   virtual bool IsScriptExecuting();
 
   // nsIHTMLContentSink
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
@@ -290,19 +290,16 @@ protected:
   nsresult ProcessSCRIPTEndTag(nsGenericHTMLElement* content,
                                bool aMalformed);
   nsresult ProcessSTYLEEndTag(nsGenericHTMLElement* content);
 
   nsresult OpenHeadContext();
   void CloseHeadContext();
 
   // nsContentSink overrides
-  virtual void PreEvaluateScript();
-  virtual void PostEvaluateScript(nsIScriptElement *aElement);
-
   void UpdateChildCounts();
 
   void NotifyInsert(nsIContent* aContent,
                     nsIContent* aChildContent,
                     PRInt32 aIndexInContainer);
   void NotifyRootInsertion();
   
   bool IsMonolithicContainer(nsHTMLTag aTag);
@@ -800,21 +797,23 @@ SinkContext::OpenContainer(const nsIPars
       {
         nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
         NS_ASSERTION(sele, "Script content isn't a script element?");
         sele->SetScriptLineNumber(aNode.GetSourceLineNumber());
       }
       break;
 
     case eHTMLTag_button:
+#ifdef MOZ_MEDIA
     case eHTMLTag_audio:
     case eHTMLTag_video:
+#endif
       content->DoneCreatingElement();
       break;
-      
+
     default:
       break;
   }
 
   return NS_OK;
 }
 
 bool
@@ -1697,18 +1696,16 @@ HTMLContentSink::DidBuildModel(bool aTer
 
     if (!bDestroying) {
       StartLayout(false);
     }
   }
 
   ScrollToRef();
 
-  mDocument->ScriptLoader()->RemoveObserver(this);
-
   // Make sure we no longer respond to document mutations.  We've flushed all
   // our notifications out, so there's no need to do anything else here.
 
   // XXXbz I wonder whether we could End() our contexts here too, or something,
   // just to make sure we no longer notify...  Or is the mIsDocumentObserver
   // thing sufficient?
   mDocument->RemoveObserver(this);
   mIsDocumentObserver = false;
@@ -1716,17 +1713,17 @@ HTMLContentSink::DidBuildModel(bool aTer
   mDocument->EndLoad();
 
   DropParserAndPerfHint();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-HTMLContentSink::SetParser(nsIParser* aParser)
+HTMLContentSink::SetParser(nsParserBase* aParser)
 {
   NS_PRECONDITION(aParser, "Should have a parser here!");
   mParser = aParser;
   return NS_OK;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLContentSink::IsFormOnStack()
@@ -2555,88 +2552,18 @@ HTMLContentSink::CloseHeadContext()
     mCurrentContext = mContextStack.ElementAt(n);
     mContextStack.RemoveElementAt(n);
   }
 }
 
 nsresult
 HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode)
 {
-  nsresult  result = NS_OK;
-
-  if (mCurrentContext) {
-    // Create content object
-    nsCOMPtr<nsIContent> element;
-    nsCOMPtr<nsINodeInfo> nodeInfo;
-    nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::link, nsnull,
-                                             kNameSpaceID_XHTML,
-                                             nsIDOMNode::ELEMENT_NODE);
-
-    result = NS_NewHTMLElement(getter_AddRefs(element), nodeInfo.forget(),
-                               NOT_FROM_PARSER);
-    NS_ENSURE_SUCCESS(result, result);
-
-    nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(element));
-
-    if (ssle) {
-      // XXX need prefs. check here.
-      if (!mInsideNoXXXTag) {
-        ssle->InitStyleLinkElement(false);
-        ssle->SetEnableUpdates(false);
-      } else {
-        ssle->InitStyleLinkElement(true);
-      }
-    }
-
-    // Add in the attributes and add the style content object to the
-    // head container.
-    result = AddAttributes(aNode, element);
-    if (NS_FAILED(result)) {
-      return result;
-    }
-
-    mCurrentContext->AddLeaf(element); // <link>s are leaves
-
-    if (ssle) {
-      ssle->SetEnableUpdates(true);
-      bool willNotify;
-      bool isAlternate;
-      result = ssle->UpdateStyleSheet(mFragmentMode ? nsnull : this,
-                                      &willNotify,
-                                      &isAlternate);
-      if (NS_SUCCEEDED(result) && willNotify && !isAlternate && !mFragmentMode) {
-        ++mPendingSheetCount;
-        mScriptLoader->AddExecuteBlocker();
-      }
-
-      // look for <link rel="next" href="url">
-      nsAutoString relVal;
-      element->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
-      if (!relVal.IsEmpty()) {
-        PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
-        bool hasPrefetch = linkTypes & PREFETCH;
-        if (hasPrefetch || (linkTypes & NEXT)) {
-          nsAutoString hrefVal;
-          element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
-          if (!hrefVal.IsEmpty()) {
-            PrefetchHref(hrefVal, element, hasPrefetch);
-          }
-        }
-        if (linkTypes & DNS_PREFETCH) {
-          nsAutoString hrefVal;
-          element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
-          if (!hrefVal.IsEmpty()) {
-            PrefetchDNS(hrefVal);
-          }
-        }
-      }
-    }
-  }
-
-  return result;
+  MOZ_NOT_REACHED("Old HTMLContentSink used for processing links.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 #ifdef DEBUG
 void
 HTMLContentSink::ForceReflow()
 {
   mCurrentContext->FlushTags();
 }
@@ -2711,120 +2638,32 @@ HTMLContentSink::UpdateChildCounts()
     SinkContext* sc = mContextStack.ElementAt(i);
 
     sc->UpdateChildCounts();
   }
 
   mCurrentContext->UpdateChildCounts();
 }
 
-void
-HTMLContentSink::PreEvaluateScript()
-{
-  // Eagerly append all pending elements (including the current body child)
-  // to the body (so that they can be seen by scripts) and force reflow.
-  SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_CALLS,
-             ("HTMLContentSink::PreEvaluateScript: flushing tags before "
-              "evaluating script"));
-
-  // XXX Should this call FlushTags()?
-  mCurrentContext->FlushText();
-}
-
-void
-HTMLContentSink::PostEvaluateScript(nsIScriptElement *aElement)
-{
-  mHTMLDocument->ScriptExecuted(aElement);
-}
-
 nsresult
 HTMLContentSink::ProcessSCRIPTEndTag(nsGenericHTMLElement *content,
                                      bool aMalformed)
 {
-  // Flush all tags up front so that we are in as stable state as possible
-  // when calling DoneAddingChildren. This may not be strictly needed since
-  // any ScriptAvailable calls will cause us to flush anyway. But it gives a
-  // warm fuzzy feeling to be in a stable state before even attempting to
-  // run scripts.
-  // It would however be needed if we properly called BeginUpdate and
-  // EndUpdate while we were inserting stuff into the DOM.
-
-  // XXX Should this call FlushTags()?
-  mCurrentContext->FlushText();
-
-  nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
-  NS_ASSERTION(sele, "Not really closing a script tag?");
-
-  if (aMalformed) {
-    // Make sure to serialize this script correctly, for nice round tripping.
-    sele->SetIsMalformed();
-  }
-  if (mFrameset) {
-    sele->PreventExecution();
-  }
-
-  // Notify our document that we're loading this script.
-  mHTMLDocument->ScriptLoading(sele);
-
-  // Now tell the script that it's ready to go. This may execute the script
-  // or return true, or neither if the script doesn't need executing.
-  bool block = sele->AttemptToExecute();
-
-  // If the act of insertion evaluated the script, we're fine.
-  // Else, block the parser till the script has loaded.
-  if (block) {
-    // If this append fails we'll never unblock the parser, but the UI will
-    // still remain responsive. There are other ways to deal with this, but
-    // the end result is always that the page gets botched, so there is no
-    // real point in making it more complicated.
-    mScriptElements.AppendObject(sele);
-  } else {
-    // This may have already happened if the script executed, but in case
-    // it didn't then remove the element so that it doesn't get stuck forever.
-    mHTMLDocument->ScriptExecuted(sele);
-  }
-
-  // If the parser got blocked, make sure to return the appropriate rv.
-  // I'm not sure if this is actually needed or not.
-  if (mParser && !mParser->IsParserEnabled()) {
-    block = true;
-  }
-
-  return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
+  MOZ_NOT_REACHED("Must not use HTMLContentSink to run scripts.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 // 3 ways to load a style sheet: inline, style src=, link tag
 // XXX What does nav do if we have SRC= and some style data inline?
 
 nsresult
 HTMLContentSink::ProcessSTYLEEndTag(nsGenericHTMLElement* content)
 {
-  nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(content);
-
-  NS_ASSERTION(ssle,
-               "html:style doesn't implement nsIStyleSheetLinkingElement");
-
-  nsresult rv = NS_OK;
-
-  if (ssle) {
-    // Note: if we are inside a noXXX tag, then we init'ed this style element
-    // with mDontLoadStyle = true, so these two calls will have no effect.
-    ssle->SetEnableUpdates(true);
-    bool willNotify;
-    bool isAlternate;
-    rv = ssle->UpdateStyleSheet(mFragmentMode ? nsnull : this,
-                                &willNotify,
-                                &isAlternate);
-    if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mFragmentMode) {
-      ++mPendingSheetCount;
-      mScriptLoader->AddExecuteBlocker();
-    }
-  }
-
-  return rv;
+  MOZ_NOT_REACHED("Old HTMLContentSink used for processing style elements.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void
 HTMLContentSink::FlushPendingNotifications(mozFlushType aType)
 {
   // Only flush tags if we're not doing the notification ourselves
   // (since we aren't reentrant)
   if (!mInNotification) {
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -901,88 +901,27 @@ nsHTMLDocument::StartDocumentLoad(const 
   }
 
   return rv;
 }
 
 void
 nsHTMLDocument::StopDocumentLoad()
 {
-  if (nsHtml5Module::sEnabled) {
-    BlockOnload();
-    if (mWriteState == eDocumentOpened) {
-      NS_ASSERTION(IsHTML(), "document.open()ed doc is not HTML?");
-
-      // Marking the document as closed, since pending scripts will be
-      // stopped by nsDocument::StopDocumentLoad() below
-      mWriteState = eDocumentClosed;
-
-      // Remove the wyciwyg channel request from the document load group
-      // that we added in Open().
-      NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
-                   "Trying to remove nonexistent wyciwyg channel!");
-      RemoveWyciwygChannel();
-      NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
-                   "nsIWyciwygChannel could not be removed!");
-    }
-    nsDocument::StopDocumentLoad();
-    UnblockOnload(false);
-    return;
-  }
-  // Code for the old parser:
-
-  // If we're writing (i.e., there's been a document.open call), then
-  // nsDocument::StopDocumentLoad will do the wrong thing and simply terminate
-  // our parser.
-  if (mWriteState != eNotWriting) {
-    Close();
-  } else {
-    nsDocument::StopDocumentLoad();
-  }
-}
-
-// static
-void
-nsHTMLDocument::DocumentWriteTerminationFunc(nsISupports *aRef)
-{
-  nsCOMPtr<nsIArray> arr = do_QueryInterface(aRef);
-  NS_ASSERTION(arr, "Must have array!");
-
-  nsCOMPtr<nsIDocument> doc = do_QueryElementAt(arr, 0);
-  NS_ASSERTION(doc, "Must have document!");
-  
-  nsCOMPtr<nsIParser> parser = do_QueryElementAt(arr, 1);
-  NS_ASSERTION(parser, "Must have parser!");
-
-  nsHTMLDocument *htmldoc = static_cast<nsHTMLDocument*>(doc.get());
-
-  // Check whether htmldoc still has the same parser.  If not, it's
-  // not for us to mess with it.
-  if (htmldoc->mParser != parser) {
-    return;
-  }
-
-  // If the document is in the middle of a document.write() call, this
-  // most likely means that script on a page document.write()'d out a
-  // script tag that did location="..." and we're right now finishing
-  // up executing the script that was written with
-  // document.write(). Since there's still script on the stack (the
-  // script that called document.write()) we don't want to release the
-  // parser now, that would cause the next document.write() call to
-  // cancel the load that was initiated by the location="..." in the
-  // script that was written out by document.write().
-
-  if (!htmldoc->mWriteLevel && htmldoc->mWriteState != eDocumentOpened) {
-    // Release the document's parser so that the call to EndLoad()
-    // doesn't just return early and set the termination function again.
-
-    htmldoc->mParser = nsnull;
-  }
-
-  htmldoc->EndLoad();
+  BlockOnload();
+
+  // Remove the wyciwyg channel request from the document load group
+  // that we added in Open() if Open() was called on this doc.
+  RemoveWyciwygChannel();
+  NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
+               "nsIWyciwygChannel could not be removed!");
+
+  nsDocument::StopDocumentLoad();
+  UnblockOnload(false);
+  return;
 }
 
 void
 nsHTMLDocument::BeginLoad()
 {
   if (IsEditingOn()) {
     // Reset() blows away all event listeners in the document, and our
     // editor relies heavily on those. Midas is turned on, to make it
@@ -993,75 +932,16 @@ nsHTMLDocument::BeginLoad()
     EditingStateChanged();
   }
   nsDocument::BeginLoad();
 }
 
 void
 nsHTMLDocument::EndLoad()
 {
-  if (mParser && mWriteState != eDocumentClosed) {
-    nsCOMPtr<nsIJSContextStack> stack =
-      do_GetService("@mozilla.org/js/xpc/ContextStack;1");
-
-    if (stack) {
-      JSContext *cx = nsnull;
-      stack->Peek(&cx);
-
-      if (cx) {
-        nsIScriptContext *scx = nsJSUtils::GetDynamicScriptContext(cx);
-
-        if (scx) {
-          // The load of the document was terminated while we're
-          // called from within JS and we have a parser (i.e. we're in
-          // the middle of doing document.write()). In stead of
-          // releasing the parser and ending the document load
-          // directly, we'll make that happen once the script is done
-          // executing. This way subsequent document.write() calls
-          // won't end up creating a new parser and interrupting other
-          // loads that were started while the script was
-          // running. I.e. this makes the following case work as
-          // expected:
-          //
-          //   document.write("foo");
-          //   location.href = "http://www.mozilla.org";
-          //   document.write("bar");
-
-          nsresult rv;
-
-          nsCOMPtr<nsIMutableArray> arr =
-            do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
-          if (NS_SUCCEEDED(rv)) {
-            rv = arr->AppendElement(static_cast<nsIDocument*>(this),
-                                    false);
-            if (NS_SUCCEEDED(rv)) {
-              rv = arr->AppendElement(mParser, false);
-              if (NS_SUCCEEDED(rv)) {
-                rv = scx->SetTerminationFunction(DocumentWriteTerminationFunc,
-                                                 arr);
-                // If we fail to set the termination function, just go ahead
-                // and EndLoad now.  The slight bugginess involved is better
-                // than leaking.
-                if (NS_SUCCEEDED(rv)) {
-                  return;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // Reset this now, since we're really done "loading" this document.written
-  // document.
-  NS_ASSERTION(mWriteState == eNotWriting || mWriteState == ePendingClose ||
-               mWriteState == eDocumentClosed, "EndLoad called early");
-  mWriteState = eNotWriting;
-
   bool turnOnEditing =
     mParser && (HasFlag(NODE_IS_EDITABLE) || mContentEditableCount > 0);
   // Note: nsDocument::EndLoad nulls out mParser.
   nsDocument::EndLoad();
   if (turnOnEditing) {
     EditingStateChanged();
   }
 }
@@ -1668,30 +1548,27 @@ nsHTMLDocument::Open(const nsAString& aC
     rv = NS_OK;
   } else {
     mParser = do_CreateInstance(kCParserCID, &rv);  
   }
 
   // This will be propagated to the parser when someone actually calls write()
   SetContentTypeInternal(contentType);
 
-  mWriteState = eDocumentOpened;
-
   if (NS_SUCCEEDED(rv)) {
     if (loadAsHtml5) {
       nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
     } else {
       nsCOMPtr<nsIHTMLContentSink> sink;
 
       rv = NS_NewHTMLContentSink(getter_AddRefs(sink), this, uri, shell,
                                  channel);
       if (NS_FAILED(rv)) {
         // Don't use a parser without a content sink.
         mParser = nsnull;
-        mWriteState = eNotWriting;
         return rv;
       }
 
       mParser->SetContentSink(sink);
     }
   }
 
   // Prepare the docshell and the document viewer for the impending
@@ -1741,65 +1618,61 @@ NS_IMETHODIMP
 nsHTMLDocument::Close()
 {
   if (!IsHTML()) {
     // No calling document.close() on XHTML!
 
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
-  nsresult rv = NS_OK;
-
-  if (mParser && mWriteState == eDocumentOpened) {
-    mPendingScripts.RemoveElement(GenerateParserKey());
-
-    mWriteState = mPendingScripts.IsEmpty() ? eDocumentClosed : ePendingClose;
-
-    ++mWriteLevel;
-    rv = mParser->Parse(EmptyString(), mParser->GetRootContextKey(),
-                        GetContentTypeInternal(), true);
-    --mWriteLevel;
-
-    // XXX Make sure that all the document.written content is
-    // reflowed.  We should remove this call once we change
-    // nsHTMLDocument::OpenCommon() so that it completely destroys the
-    // earlier document's content and frame hierarchy.  Right now, it
-    // re-uses the earlier document's root content object and
-    // corresponding frame objects.  These re-used frame objects think
-    // that they have already been reflowed, so they drop initial
-    // reflows.  For certain cases of document.written content, like a
-    // frameset document, the dropping of the initial reflow means
-    // that we end up in document.close() without appended any reflow
-    // commands to the reflow queue and, consequently, without adding
-    // the dummy layout request to the load group.  Since the dummy
-    // layout request is not added to the load group, the onload
-    // handler of the frameset fires before the frames get reflowed
-    // and loaded.  That is the long explanation for why we need this
-    // one line of code here!
-    // XXXbz as far as I can tell this may not be needed anymore; all
-    // the testcases in bug 57636 pass without this line...  Leaving
-    // it be for now, though.  In any case, there's no reason to do
-    // this if we have no presshell, since in that case none of the
-    // above about reusing frames applies.
-    if (GetShell()) {
-      FlushPendingNotifications(Flush_Layout);
-    }
-
-    // Remove the wyciwyg channel request from the document load group
-    // that we added in OpenCommon().  If all other requests between
-    // document.open() and document.close() have completed, then this
-    // method should cause the firing of an onload event.
-    NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::Close(): Trying to remove "
-                 "nonexistent wyciwyg channel!");
-    RemoveWyciwygChannel();
-    NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Close(): "
-                 "nsIWyciwygChannel could not be removed!");
+  if (!mParser || !mParser->IsScriptCreated()) {
+    return NS_OK;
   }
 
-  return NS_OK;
+  ++mWriteLevel;
+  nsresult rv = mParser->Parse(EmptyString(), nsnull,
+                               GetContentTypeInternal(), true);
+  --mWriteLevel;
+
+  // XXX Make sure that all the document.written content is
+  // reflowed.  We should remove this call once we change
+  // nsHTMLDocument::OpenCommon() so that it completely destroys the
+  // earlier document's content and frame hierarchy.  Right now, it
+  // re-uses the earlier document's root content object and
+  // corresponding frame objects.  These re-used frame objects think
+  // that they have already been reflowed, so they drop initial
+  // reflows.  For certain cases of document.written content, like a
+  // frameset document, the dropping of the initial reflow means
+  // that we end up in document.close() without appended any reflow
+  // commands to the reflow queue and, consequently, without adding
+  // the dummy layout request to the load group.  Since the dummy
+  // layout request is not added to the load group, the onload
+  // handler of the frameset fires before the frames get reflowed
+  // and loaded.  That is the long explanation for why we need this
+  // one line of code here!
+  // XXXbz as far as I can tell this may not be needed anymore; all
+  // the testcases in bug 57636 pass without this line...  Leaving
+  // it be for now, though.  In any case, there's no reason to do
+  // this if we have no presshell, since in that case none of the
+  // above about reusing frames applies.
+  //
+  // XXXhsivonen keeping this around for bug 577508 / 253951 still :-(
+  if (GetShell()) {
+    FlushPendingNotifications(Flush_Layout);
+  }
+
+  // Removing the wyciwygChannel here is wrong when document.close() is
+  // called from within the document itself. However, legacy requires the
+  // channel to be removed here. Otherwise, the load event never fires.
+  NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::Close(): Trying to remove "
+               "nonexistent wyciwyg channel!");
+  RemoveWyciwygChannel();
+  NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Close(): "
+               "nsIWyciwygChannel could not be removed!");
+  return rv;
 }
 
 nsresult
 nsHTMLDocument::WriteCommon(JSContext *cx,
                             const nsAString& aText,
                             bool aNewlineTerminate)
 {
   mTooDeepWriteRecursion =
@@ -1810,31 +1683,27 @@ nsHTMLDocument::WriteCommon(JSContext *c
     // No calling document.write*() on XHTML!
 
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   nsresult rv = NS_OK;
 
   void *key = GenerateParserKey();
-  if (mWriteState == eDocumentClosed ||
-      (mWriteState == ePendingClose &&
-       !mPendingScripts.Contains(key)) ||
-      (mParser && !mParser->IsInsertionPointDefined())) {
+  if (mParser && !mParser->IsInsertionPointDefined()) {
     if (mExternalScriptsBeingEvaluated) {
       // Instead of implying a call to document.open(), ignore the call.
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                       "DOM Events", this,
                                       nsContentUtils::eDOM_PROPERTIES,
                                       "DocumentWriteIgnored",
                                       nsnull, 0,
                                       mDocumentURI);
       return NS_OK;
     }
-    mWriteState = eDocumentClosed;
     mParser->Terminate();
     NS_ASSERTION(!mParser, "mParser should have been null'd out");
   }
 
   if (!mParser) {
     if (mExternalScriptsBeingEvaluated) {
       // Instead of implying a call to document.open(), ignore the call.
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
@@ -1856,18 +1725,18 @@ nsHTMLDocument::WriteCommon(JSContext *c
       return rv;
     }
     NS_ABORT_IF_FALSE(!JS_IsExceptionPending(cx),
                       "Open() succeeded but JS exception is pending");
   }
 
   static NS_NAMED_LITERAL_STRING(new_line, "\n");
 
-  // Save the data in cache
-  if (mWyciwygChannel) {
+  // Save the data in cache if the write isn't from within the doc
+  if (mWyciwygChannel && !key) {
     if (!aText.IsEmpty()) {
       mWyciwygChannel->WriteToCacheEntry(aText);
     }
 
     if (aNewlineTerminate) {
       mWyciwygChannel->WriteToCacheEntry(new_line);
     }
   }
@@ -1876,21 +1745,21 @@ nsHTMLDocument::WriteCommon(JSContext *c
 
   // This could be done with less code, but for performance reasons it
   // makes sense to have the code for two separate Parse() calls here
   // since the concatenation of strings costs more than we like. And
   // why pay that price when we don't need to?
   if (aNewlineTerminate) {
     rv = mParser->Parse(aText + new_line,
                         key, GetContentTypeInternal(),
-                        (mWriteState == eNotWriting || (mWriteLevel > 1)));
+                        false);
   } else {
     rv = mParser->Parse(aText,
                         key, GetContentTypeInternal(),
-                        (mWriteState == eNotWriting || (mWriteLevel > 1)));
+                        false);
   }
 
   --mWriteLevel;
 
   mTooDeepWriteRecursion = (mWriteLevel != 0 && mTooDeepWriteRecursion);
 
   return rv;
 }
@@ -1935,40 +1804,16 @@ nsHTMLDocument::GetElementsByName(const 
 
   // Transfer ownership
   list.forget(aReturn);
 
   return NS_OK;
 }
 
 void
-nsHTMLDocument::ScriptLoading(nsIScriptElement *aScript)
-{
-  if (mWriteState == eNotWriting) {
-    return;
-  }
-
-  mPendingScripts.AppendElement(aScript);
-}
-
-void
-nsHTMLDocument::ScriptExecuted(nsIScriptElement *aScript)
-{
-  if (mWriteState == eNotWriting) {
-    return;
-  }
-
-  mPendingScripts.RemoveElement(aScript);
-  if (mPendingScripts.IsEmpty() && mWriteState == ePendingClose) {
-    // The last pending script just finished, terminate our parser now.
-    mWriteState = eDocumentClosed;
-  }
-}
-
-void
 nsHTMLDocument::AddedForm()
 {
   ++mNumForms;
 }
 
 void
 nsHTMLDocument::RemovedForm()
 {
@@ -2406,17 +2251,17 @@ nsHTMLDocument::GenerateParserKey(void)
   if (nsHtml5Module::sEnabled) {
     nsIScriptElement* script = mScriptLoader->GetCurrentParserInsertedScript();
     if (script && mParser && mParser->IsScriptCreated()) {
       nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
       if (creatorParser != mParser) {
         // Make scripts that aren't inserted by the active parser of this document
         // participate in the context of the script that document.open()ed 
         // this document.
-        return mParser->GetRootContextKey();
+        return nsnull;
       }
     }
     return script;
   } else {
     return mScriptLoader->GetCurrentScript();
   }
 }
 
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -144,19 +144,16 @@ public:
   }
 
 
   virtual nsresult ResolveName(const nsAString& aName,
                                nsIContent *aForm,
                                nsISupports **aResult,
                                nsWrapperCache **aCache);
 
-  virtual void ScriptLoading(nsIScriptElement *aScript);
-  virtual void ScriptExecuted(nsIScriptElement *aScript);
-
   virtual void AddedForm();
   virtual void RemovedForm();
   virtual PRInt32 GetNumFormsSynchronous();
   virtual void TearingDownEditor(nsIEditor *aEditor);
   virtual void SetIsXHTML(bool aXHTML) { mIsRegularHTML = !aXHTML; }
   virtual void SetDocWriteDisabled(bool aDisabled)
   {
     mDisableDocWrite = aDisabled;
@@ -270,39 +267,22 @@ protected:
                                       nsACString& aCharset);
   static bool TryDefaultCharset(nsIMarkupDocumentViewer* aMarkupDV,
                                   PRInt32& aCharsetSource,
                                   nsACString& aCharset);
 
   // Override so we can munge the charset on our wyciwyg channel as needed.
   virtual void SetDocumentCharacterSet(const nsACString& aCharSetID);
 
-  // mWriteState tracks the status of this document if the document is being
-  // entirely created by script. In the normal load case, mWriteState will be
-  // eNotWriting. Once document.open has been called (either implicitly or
-  // explicitly), mWriteState will be eDocumentOpened. When document.close has
-  // been called, mWriteState will become eDocumentClosed if there have been no
-  // external script loads in the meantime. If there have been, then mWriteState
-  // becomes ePendingClose, indicating that we might still be writing, but that
-  // we shouldn't process any further close() calls.
-  enum {
-    eNotWriting,
-    eDocumentOpened,
-    ePendingClose,
-    eDocumentClosed
-  } mWriteState;
-
   // Tracks if we are currently processing any document.write calls (either
   // implicit or explicit). Note that if a write call writes out something which
   // would block the parser, then mWriteLevel will be incorrect until the parser
   // finishes processing that script.
   PRUint32 mWriteLevel;
 
-  nsAutoTArray<nsIScriptElement*, 1> mPendingScripts;
-
   // Load flags of the document's channel
   PRUint32 mLoadFlags;
 
   bool mIsFrameset;
 
   bool mTooDeepWriteRecursion;
 
   bool mDisableDocWrite;
--- a/content/html/document/src/nsIHTMLDocument.h
+++ b/content/html/document/src/nsIHTMLDocument.h
@@ -44,19 +44,18 @@
 class nsIDOMHTMLFormElement;
 class nsIContent;
 class nsIScriptElement;
 class nsIEditor;
 class nsContentList;
 class nsWrapperCache;
 
 #define NS_IHTMLDOCUMENT_IID \
-{ 0x51a360fa, 0xd659, 0x4d85, \
-  { 0xa5, 0xc5, 0x4a, 0xbb, 0x0d, 0x97, 0x0f, 0x7a } }
-
+{ 0xa921276f, 0x5e70, 0x42e0, \
+  { 0xb8, 0x36, 0x7e, 0x6a, 0xb8, 0x30, 0xb3, 0xc0 } }
 
 /**
  * HTML document extensions to nsIDocument.
  */
 class nsIHTMLDocument : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IHTMLDOCUMENT_IID)
@@ -67,28 +66,16 @@ public:
   virtual void SetCompatibilityMode(nsCompatibility aMode) = 0;
 
   virtual nsresult ResolveName(const nsAString& aName,
                                nsIContent *aForm,
                                nsISupports **aResult,
                                nsWrapperCache **aCache) = 0;
 
   /**
-   * Called from the script loader to notify this document that a new
-   * script is being loaded.
-   */
-  virtual void ScriptLoading(nsIScriptElement *aScript) = 0;
-
-  /**
-   * Called from the script loader to notify this document that a script
-   * just finished executing.
-   */
-  virtual void ScriptExecuted(nsIScriptElement *aScript) = 0;
-
-  /**
    * Called when form->BindToTree() is called so that document knows
    * immediately when a form is added
    */
   virtual void AddedForm() = 0;
   /**
    * Called when form->SetDocument() is called so that document knows
    * immediately when a form is removed
    */
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -202,17 +202,17 @@ nsXMLContentSink::WillBuildModel(nsDTDMo
   WillBuildModelImpl();
 
   // Notify document that the load is beginning
   mDocument->BeginLoad();
 
   // Check for correct load-command for maybe prettyprinting
   if (mPrettyPrintXML) {
     nsCAutoString command;
-    mParser->GetCommand(command);
+    GetParser()->GetCommand(command);
     if (!command.EqualsLiteral("view")) {
       mPrettyPrintXML = false;
     }
   }
   
   return NS_OK;
 }
 
@@ -322,17 +322,16 @@ nsXMLContentSink::DidBuildModel(bool aTe
     nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
     mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
     // Since the processor now holds a reference to us we drop our reference
     // to it to avoid owning cycles
     mXSLTProcessor = nsnull;
   }
   else {
     // Kick off layout for non-XSLT transformed documents.
-    mDocument->ScriptLoader()->RemoveObserver(this);
 
     // Check if we want to prettyprint
     MaybePrettyPrint();
 
     bool startLayout = true;
     
     if (mPrettyPrinting) {
       NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
@@ -414,18 +413,16 @@ nsXMLContentSink::OnTransformDone(nsresu
     // document to display.
     mDocument = aResultDocument;
     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
     if (htmlDoc) {
       htmlDoc->SetDocWriteDisabled(false);
     }
   }
 
-  originalDocument->ScriptLoader()->RemoveObserver(this);
-
   // Notify document observers that all the content has been stuck
   // into the document.  
   // XXX do we need to notify for things like PIs?  Or just the
   // documentElement?
   nsIContent *rootElement = mDocument->GetRootElement();
   if (rootElement) {
     NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
                  "rootElement not in doc?");
@@ -471,17 +468,17 @@ nsXMLContentSink::WillInterrupt(void)
 
 NS_IMETHODIMP
 nsXMLContentSink::WillResume(void)
 {
   return WillResumeImpl();
 }
 
 NS_IMETHODIMP
-nsXMLContentSink::SetParser(nsIParser* aParser)
+nsXMLContentSink::SetParser(nsParserBase* aParser)
 {
   NS_PRECONDITION(aParser, "Should have a parser here!");
   mParser = aParser;
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
@@ -500,17 +497,17 @@ nsXMLContentSink::CreateElement(const PR
   rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
       || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
     ) {
     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
     sele->SetScriptLineNumber(aLineNumber);
-    sele->SetCreatorParser(mParser);
+    sele->SetCreatorParser(GetParser());
     mConstrainSize = false;
   }
 
   // XHTML needs some special attention
   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
     mPrettyPrintHasFactoredElements = true;
   }
   else {
@@ -591,31 +588,28 @@ nsXMLContentSink::CloseElement(nsIConten
     mConstrainSize = true; 
     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
 
     if (mPreventScriptExecution) {
       sele->PreventExecution();
       return NS_OK;
     }
 
+    // Always check the clock in nsContentSink right after a script
+    StopDeflecting();
+
     // Now tell the script that it's ready to go. This may execute the script
     // or return true, or neither if the script doesn't need executing.
     bool block = sele->AttemptToExecute();
 
-    // If the act of insertion evaluated the script, we're fine.
-    // Else, block the parser till the script has loaded.
-    if (block) {
-      mScriptElements.AppendObject(sele);
-    }
-
     // If the parser got blocked, make sure to return the appropriate rv.
     // I'm not sure if this is actually needed or not.
     if (mParser && !mParser->IsParserEnabled()) {
       // XXX The HTML sink doesn't call BlockParser here, why do we?
-      mParser->BlockParser();
+      GetParser()->BlockParser();
       block = true;
     }
 
     return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
   }
   
   nsresult rv = NS_OK;
   if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
@@ -627,20 +621,20 @@ nsXMLContentSink::CloseElement(nsIConten
   else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
     if (ssle) {
       ssle->SetEnableUpdates(true);
       bool willNotify;
       bool isAlternate;
-      rv = ssle->UpdateStyleSheet(mFragmentMode ? nsnull : this,
+      rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nsnull : this,
                                   &willNotify,
                                   &isAlternate);
-      if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mFragmentMode) {
+      if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
         ++mPendingSheetCount;
         mScriptLoader->AddExecuteBlocker();
       }
     }
     // Look for <link rel="dns-prefetch" href="hostname">
     // and look for <link rel="next" href="hostname"> like in HTML sink
     if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
       nsAutoString relVal;
@@ -728,17 +722,17 @@ nsXMLContentSink::ProcessStyleLink(nsICo
                                    const nsSubstring& aType,
                                    const nsSubstring& aMedia)
 {
   nsresult rv = NS_OK;
   mPrettyPrintXML = false;
 
   nsCAutoString cmd;
   if (mParser)
-    mParser->GetCommand(cmd);
+    GetParser()->GetCommand(cmd);
   if (cmd.EqualsASCII(kLoadAsData))
     return NS_OK; // Do not load stylesheets when loading as data
 
   NS_ConvertUTF16toUTF8 type(aType);
   if (type.EqualsIgnoreCase(TEXT_XSL) ||
       type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
       type.EqualsIgnoreCase(TEXT_XML) ||
       type.EqualsIgnoreCase(APPLICATION_XML)) {
@@ -1072,19 +1066,23 @@ nsXMLContentSink::HandleStartElement(con
     }
   }
 
   // Some HTML nodes need DoneCreatingElement() called to initialize
   // properly (eg form state restoration).
   if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
     if (nodeInfo->NameAtom() == nsGkAtoms::input ||
         nodeInfo->NameAtom() == nsGkAtoms::button ||
-        nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
-        nodeInfo->NameAtom() == nsGkAtoms::audio || 
-        nodeInfo->NameAtom() == nsGkAtoms::video) {
+        nodeInfo->NameAtom() == nsGkAtoms::menuitem
+#ifdef MOZ_MEDIA
+        ||
+        nodeInfo->NameAtom() == nsGkAtoms::audio ||
+        nodeInfo->NameAtom() == nsGkAtoms::video
+#endif
+        ) {
       content->DoneCreatingElement();
     } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
       mCurrentHead = content;
     }
   }
 
   if (IsMonolithicContainer(nodeInfo)) {
     mInMonolithicContainer++;
@@ -1319,24 +1317,24 @@ nsXMLContentSink::HandleProcessingInstru
   DidAddContent();
 
   if (ssle) {
     // This is an xml-stylesheet processing instruction... but it might not be
     // a CSS one if the type is set to something else.
     ssle->SetEnableUpdates(true);
     bool willNotify;
     bool isAlternate;
-    rv = ssle->UpdateStyleSheet(mFragmentMode ? nsnull : this,
+    rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nsnull : this,
                                 &willNotify,
                                 &isAlternate);
     NS_ENSURE_SUCCESS(rv, rv);
     
     if (willNotify) {
       // Successfully started a stylesheet load
-      if (!isAlternate && !mFragmentMode) {
+      if (!isAlternate && !mRunsToCompletion) {
         ++mPendingSheetCount;
         mScriptLoader->AddExecuteBlocker();
       }
 
       return NS_OK;
     }
   }
 
@@ -1676,8 +1674,31 @@ nsXMLContentSink::IsMonolithicContainer(
           (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
            aNodeInfo->NameAtom() == nsGkAtoms::select ||
            aNodeInfo->NameAtom() == nsGkAtoms::object ||
            aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
           (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
           (aNodeInfo->NameAtom() == nsGkAtoms::math))
           );
 }
+
+void
+nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
+{
+  if (mParser && mParser->IsParserEnabled()) {
+    GetParser()->ContinueInterruptedParsing();
+  }
+}
+
+void
+nsXMLContentSink::ContinueInterruptedParsingAsync()
+{
+  nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
+    &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
+
+  NS_DispatchToCurrentThread(ev);
+}
+
+nsIParser*
+nsXMLContentSink::GetParser()
+{
+  return static_cast<nsIParser*>(mParser.get());
+}
--- a/content/xml/document/src/nsXMLContentSink.h
+++ b/content/xml/document/src/nsXMLContentSink.h
@@ -92,34 +92,40 @@ public:
   NS_DECL_NSIEXPATSINK
 
   // nsIContentSink
   NS_IMETHOD WillParse(void);
   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   NS_IMETHOD DidBuildModel(bool aTerminated);
   NS_IMETHOD WillInterrupt(void);
   NS_IMETHOD WillResume(void);
-  NS_IMETHOD SetParser(nsIParser* aParser);  
+  NS_IMETHOD SetParser(nsParserBase* aParser);
   virtual void FlushPendingNotifications(mozFlushType aType);
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
   virtual nsISupports *GetTarget();
   virtual bool IsScriptExecuting();
+  virtual void ContinueInterruptedParsingAsync();
 
   // nsITransformObserver
   NS_IMETHOD OnDocumentCreated(nsIDocument *aResultDocument);
   NS_IMETHOD OnTransformDone(nsresult aResult, nsIDocument *aResultDocument);
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate,
                               nsresult aStatus);
   static bool ParsePIData(const nsString &aData, nsString &aHref,
                           nsString &aTitle, nsString &aMedia,
                           bool &aIsAlternate);
 
 protected:
+
+  nsIParser* GetParser();
+
+  void ContinueInterruptedParsingIfEnabled();
+
   // Start layout.  If aIgnorePendingSheets is true, this will happen even if
   // we still have stylesheet loads pending.  Otherwise, we'll wait until the
   // stylesheets are all done loading.
   virtual void MaybeStartLayout(bool aIgnorePendingSheets);
 
   virtual nsresult AddAttributes(const PRUnichar** aNode, nsIContent* aContent);
   nsresult AddText(const PRUnichar* aString, PRInt32 aLength);
 
--- a/content/xml/document/src/nsXMLFragmentContentSink.cpp
+++ b/content/xml/document/src/nsXMLFragmentContentSink.cpp
@@ -161,17 +161,17 @@ nsresult
 NS_NewXMLFragmentContentSink(nsIFragmentContentSink** aResult)
 {
   return NewXMLFragmentContentSinkHelper(aResult);
 }
 
 nsXMLFragmentContentSink::nsXMLFragmentContentSink()
  : mParseError(false)
 {
-  mFragmentMode = true;
+  mRunsToCompletion = true;
 }
 
 nsXMLFragmentContentSink::~nsXMLFragmentContentSink()
 {
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLFragmentContentSink)
   NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink)
@@ -206,17 +206,17 @@ nsXMLFragmentContentSink::WillBuildModel
   mRoot = do_QueryInterface(frag);
   
   return rv;
 }
 
 NS_IMETHODIMP 
 nsXMLFragmentContentSink::DidBuildModel(bool aTerminated)
 {
-  nsCOMPtr<nsIParser> kungFuDeathGrip(mParser);
+  nsRefPtr<nsParserBase> kungFuDeathGrip(mParser);
 
   // Drop our reference to the parser to get rid of a circular
   // reference.
   mParser = nsnull;
 
   return NS_OK;
 }
 
--- a/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
+++ b/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
@@ -110,17 +110,17 @@ public:
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSIINTERFACEREQUESTOR
 
     // nsIContentSink
     NS_IMETHOD WillParse(void) { return NS_OK; }
     NS_IMETHOD DidBuildModel(bool aTerminated);
     NS_IMETHOD WillInterrupt(void) { return NS_OK; }
     NS_IMETHOD WillResume(void) { return NS_OK; }
-    NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+    NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
     virtual void FlushPendingNotifications(mozFlushType aType) { }
     NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
     virtual nsISupports *GetTarget() { return nsnull; }
 
 private:
     nsRefPtr<txStylesheetCompiler> mCompiler;
     nsCOMPtr<nsIStreamListener> mListener;
     bool mCheckedForXML;
--- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp
@@ -333,19 +333,23 @@ txMozillaXMLOutput::endElement()
             // Else, add this script element to the array of loading scripts.
             if (block) {
                 rv = mNotifier->AddScriptElement(sele);
                 NS_ENSURE_SUCCESS(rv, rv);
             }
         } else if (ns == kNameSpaceID_XHTML &&
                    (localName == nsGkAtoms::input ||
                     localName == nsGkAtoms::button ||
-                    localName == nsGkAtoms::menuitem ||
+                    localName == nsGkAtoms::menuitem
+#ifdef MOZ_MEDIA
+                     ||
                     localName == nsGkAtoms::audio ||
-                    localName == nsGkAtoms::video )) {
+                    localName == nsGkAtoms::video
+#endif
+                  )) {
           element->DoneCreatingElement();
         }   
     }
 
     if (mCreatingNewDocument) {
         // Handle all sorts of stylesheets
         nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
             do_QueryInterface(mCurrentNode);
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -295,17 +295,17 @@ XULContentSinkImpl::WillInterrupt(void)
 NS_IMETHODIMP 
 XULContentSinkImpl::WillResume(void)
 {
     // XXX Notify the docshell, if necessary
     return NS_OK;
 }
 
 NS_IMETHODIMP 
-XULContentSinkImpl::SetParser(nsIParser* aParser)
+XULContentSinkImpl::SetParser(nsParserBase* aParser)
 {
     NS_IF_RELEASE(mParser);
     mParser = aParser;
     NS_IF_ADDREF(mParser);
     return NS_OK;
 }
 
 NS_IMETHODIMP 
--- a/content/xul/document/src/nsXULContentSink.h
+++ b/content/xul/document/src/nsXULContentSink.h
@@ -69,17 +69,17 @@ public:
     NS_DECL_NSIEXPATSINK
 
     // nsIContentSink
     NS_IMETHOD WillParse(void) { return NS_OK; }
     NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
     NS_IMETHOD DidBuildModel(bool aTerminated);
     NS_IMETHOD WillInterrupt(void);
     NS_IMETHOD WillResume(void);
-    NS_IMETHOD SetParser(nsIParser* aParser);
+    NS_IMETHOD SetParser(nsParserBase* aParser);
     virtual void FlushPendingNotifications(mozFlushType aType) { }
     NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
     virtual nsISupports *GetTarget();
 
     /**
      * Initialize the content sink, giving it an nsIDocument object
      * with which to communicate with the outside world, and an
      * nsXULPrototypeDocument to build.
@@ -175,13 +175,13 @@ protected:
     ContextStack mContextStack;
 
     nsWeakPtr              mDocument;             // [OWNER]
     nsCOMPtr<nsIURI>       mDocumentURL;          // [OWNER]
 
     nsRefPtr<nsXULPrototypeDocument> mPrototype;  // [OWNER]
 
     // We use regular pointer b/c of funky exports on nsIParser:
-    nsIParser*             mParser;               // [OWNER]
+    nsParserBase*         mParser;               // [OWNER]
     nsCOMPtr<nsIScriptSecurityManager> mSecMan;
 };
 
 #endif /* nsXULContentSink_h__ */
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -140,17 +140,16 @@
 #include "nsDOMError.h"
 #include "nsIDOMDOMException.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMNamedNodeMap.h"
 #include "nsIDOMDOMStringList.h"
 #include "nsIDOMDOMTokenList.h"
 #include "nsIDOMDOMSettableTokenList.h"
-#include "nsIDOMMozBrowserFrameElement.h"
 
 #include "nsDOMStringMap.h"
 
 // HTMLFormElement helper includes
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMHTMLCollection.h"
@@ -348,16 +347,17 @@
 #include "nsIXULTemplateBuilder.h"
 #include "nsTreeColumns.h"
 #endif
 #include "nsIDOMXPathException.h"
 #include "nsIDOMXPathExpression.h"
 #include "nsIDOMNSXPathExpression.h"
 #include "nsIDOMXPathNSResolver.h"
 #include "nsIDOMXPathResult.h"
+#include "nsIDOMMozBrowserFrame.h"
 
 #include "nsIDOMGetSVGDocument.h"
 #include "nsIDOMSVGAElement.h"
 #include "nsIDOMSVGAltGlyphElement.h"
 #include "nsIDOMSVGAngle.h"
 #include "nsIDOMSVGAnimatedAngle.h"
 #include "nsIDOMSVGAnimatedBoolean.h"
 #include "nsIDOMSVGAnimatedEnum.h"
@@ -2687,17 +2687,17 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLFormElement, nsIDOMHTMLFormElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLFormElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLFrameElement, nsIDOMHTMLFrameElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLFrameElement)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozBrowserFrameElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozBrowserFrame)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLFrameSetElement, nsIDOMHTMLFrameSetElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLFrameSetElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
@@ -2719,17 +2719,17 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(HTMLHtmlElement, nsIDOMHTMLHtmlElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLHtmlElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLIFrameElement, nsIDOMHTMLIFrameElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLIFrameElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMGetSVGDocument)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozBrowserFrameElement)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozBrowserFrame)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLImageElement, nsIDOMHTMLImageElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLImageElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -103,16 +103,17 @@
 // Force PR_LOGGING so we can get JS strict warnings even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 #include "prthread.h"
 
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/Telemetry.h"
 
 #include "sampler.h"
 
 using namespace mozilla;
 
 const size_t gStackSize = 8192;
 
 #ifdef PR_LOGGING
@@ -141,16 +142,18 @@ static PRLogModuleInfo* gJSDiagnostics;
 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
 
 // if you add statics here, add them to the list in nsJSRuntime::Startup
 
 static nsITimer *sGCTimer;
 static nsITimer *sShrinkGCBuffersTimer;
 static nsITimer *sCCTimer;
 
+static PRTime sLastCCEndTime;
+
 static bool sGCHasRun;
 
 // The number of currently pending document loads. This count isn't
 // guaranteed to always reflect reality and can't easily as we don't
 // have an easy place to know when a load ends or is interrupted in
 // all cases. This counter also gets reset if we end up GC'ing while
 // we're waiting for a slow page to load. IOW, this count may be 0
 // even when there are pending loads.
@@ -3271,18 +3274,25 @@ nsJSContext::CycleCollectNow(nsICycleCol
   sCCollectedWaitingForGC += collected;
 
   // If we collected a substantial amount of cycles, poke the GC since more objects
   // might be unreachable now.
   if (sCCollectedWaitingForGC > 250) {
     PokeGC();
   }
 
+  PRTime now = PR_Now();
+
+  if (sLastCCEndTime) {
+    PRUint32 timeBetween = (PRUint32)(start - sLastCCEndTime) / PR_USEC_PER_SEC;
+    Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween);
+  }
+  sLastCCEndTime = now;
+
   if (sPostGCEventsToConsole) {
-    PRTime now = PR_Now();
     PRTime delta = 0;
     if (sFirstCollectionTime) {
       delta = now - sFirstCollectionTime;
     } else {
       sFirstCollectionTime = now;
     }
 
     NS_NAMED_LITERAL_STRING(kFmt,
@@ -3610,16 +3620,17 @@ nsJSRuntime::ParseVersion(const nsString
 
 //static
 void
 nsJSRuntime::Startup()
 {
   // initialize all our statics, so that we can restart XPCOM
   sGCTimer = sCCTimer = nsnull;
   sGCHasRun = false;
+  sLastCCEndTime = 0;
   sPendingLoadCount = 0;
   sLoadingInProgress = false;
   sCCollectedWaitingForGC = 0;
   sPostGCEventsToConsole = false;
   gNameSpaceManager = nsnull;
   sRuntimeService = nsnull;
   sRuntime = nsnull;
   sIsInitialized = false;
--- a/dom/interfaces/html/Makefile.in
+++ b/dom/interfaces/html/Makefile.in
@@ -111,17 +111,17 @@ SDK_XPIDLSRCS =					\
 	nsIDOMTimeRanges.idl		\
 	nsIDOMHTMLByteRanges.idl		\
 	nsIDOMHTMLMediaElement.idl		\
 	nsIDOMHTMLSourceElement.idl		\
 	nsIDOMHTMLVideoElement.idl		\
 	nsIDOMHTMLAudioElement.idl		\
 	nsIDOMValidityState.idl		\
 	nsIDOMDOMStringMap.idl		\
-	nsIDOMMozBrowserFrameElement.idl	\
+	nsIDOMMozBrowserFrame.idl		\
 	$(NULL)
 
 XPIDLSRCS = 					\
 	nsIDOMHTMLCanvasElement.idl		\
 	nsIDOMHTMLUnknownElement.idl \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/html/nsIDOMMozBrowserFrame.idl
@@ -0,0 +1,38 @@
+/* -*- Mode: IDL; 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 "nsISupports.idl"
+
+[scriptable, uuid(4CAFE116-581B-4194-B0DE-7F02378FC51D)]
+interface nsIDOMMozBrowserFrame : nsISupports
+{
+  /**
+   * <iframe> and <frame> elements may have the mozbrowser attribute.
+   *
+   * The mozbrowser attribute has no effect unless the <iframe> or <frame>
+   * element is contained in a document privileged to create browser frames.
+   *
+   * An <iframe> or <frame> element in a privileged document with the
+   * mozbrowser attribute emits mozBrowserPropertyChange events when various
+   * things happen inside the frame.
+   *
+   * The mozBrowserPropertyChangeEvent object has two properties:
+   *
+   *   property: The property which changed
+   *   value:    The property's new value
+   *
+   * Currently, the |property| field may take on the following values:
+   *
+   *   'location': The content window's location changed. |value| gives the new
+   *               URI.
+   *
+   *   'loading':  The content window started loading a new page (|value| ==
+   *               'start') or finished loading (|value| == 'stop').
+   *
+   */
+  attribute boolean mozbrowser;
+};
deleted file mode 100644
--- a/dom/interfaces/html/nsIDOMMozBrowserFrameElement.idl
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla code.
- *
- * The Initial Developer of the Original Code is the Mozilla Foundation.
- *
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Justin Lebar <justin.lebar@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsISupports.idl"
-
-[scriptable, function, uuid(37687881-1801-489f-ad03-7af651a93448)]
-interface nsIDOMMozGetContentStateCallback : nsISupports
-{
-  void callback(in DOMString value);
-};
-
-[scriptable, uuid(2ff0f421-64e4-4186-b0dd-619629f46048)]
-interface nsIDOMMozBrowserFrameElement : nsISupports
-{
-  /**
-   * If true, a privileged page can call mozGetContentState on this element.
-   * If false, mozGetContentState will fail.
-   */
-  attribute boolean mozBrowser;
-
-  /**
-   * Get a piece of state from this element's content window, returning its
-   * value via |callback|.
-   *
-   * At the moment, the only valid property is "location", which returns the
-   * content window's location.  Passing any other property causes an error.
-   *
-   * If the iframe's mozBrowser is false, or if the calling window is not
-   * privileged, this function fails.
-   */
-  void mozGetContentState(in DOMString property,
-                          in nsIDOMMozGetContentStateCallback callback);
-};
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -915,16 +915,18 @@ DOMStorageImpl::SetDBValue(const nsAStri
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRInt32 offlineAppPermission;
   PRInt32 quota;
   PRInt32 warnQuota;
   offlineAppPermission = GetQuota(mDomain, &quota, &warnQuota,
                                   CanUseChromePersist());
 
+  CacheKeysFromDB();
+
   PRInt32 usage;
   rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota,
                          !IS_PERMISSION_ALLOWED(offlineAppPermission),
                          &usage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (warnQuota >= 0 && usage > warnQuota) {
     // try to include the window that exceeded the warn quota
--- a/dom/src/storage/nsDOMStoragePersistentDB.cpp
+++ b/dom/src/storage/nsDOMStoragePersistentDB.cpp
@@ -515,18 +515,16 @@ nsDOMStoragePersistentDB::SetKey(DOMStor
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRInt32 usage = 0;
   if (!aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage).IsEmpty()) {
     rv = GetUsage(aStorage, aExcludeOfflineFromUsage, &usage);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  aStorage->CacheKeysFromDB();
-
   usage += aKey.Length() + aValue.Length();
 
   nsAutoString previousValue;
   bool secure;
   rv = aStorage->GetCachedValue(aKey, previousValue, &secure);
   if (NS_SUCCEEDED(rv)) {
     if (!aSecure && secure)
       return NS_ERROR_DOM_SECURITY_ERR;
--- a/dom/tests/mochitest/general/Makefile.in
+++ b/dom/tests/mochitest/general/Makefile.in
@@ -69,17 +69,21 @@ include $(topsrcdir)/config/rules.mk
 		test_nodesFromRect.html \
 		test_frameElementWrapping.html \
 		file_frameElementWrapping.html \
 		test_framedhistoryframes.html \
 		test_windowedhistoryframes.html \
 		test_focusrings.xul \
 		file_moving_xhr.html \
 		test_vibrator.html \
-		test_getContentState.html \
+		browserFrameHelpers.js \
+		test_browserFrame1.html \
+		test_browserFrame2.html \
+		test_browserFrame3.html \
+		test_browserFrame4.html \
 		$(NULL)
 
 _CHROME_FILES = \
 		test_innerScreen.xul \
 		test_offsets.xul \
 		test_offsets.js \
 		$(NULL)
 
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/browserFrameHelpers.js
@@ -0,0 +1,62 @@
+"use strict";
+
+// Helpers for managing the browser frame preferences.
+
+const browserFrameHelpers = {
+  'getEnabledPref': function() {
+    try {
+      return SpecialPowers.getBoolPref('dom.mozBrowserFramesEnabled');
+    }
+    catch(e) {
+      return undefined;
+    }
+  },
+
+  'getWhitelistPref': function() {
+    try {
+      return SpecialPowers.getCharPref('dom.mozBrowserFramesWhitelist');
+    }
+    catch(e) {
+      return undefined;
+    }
+  },
+
+  'setEnabledPref': function(enabled) {
+    if (enabled !== undefined) {
+      SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', enabled);
+    }
+    else {
+      SpecialPowers.clearUserPref('dom.mozBrowserFramesEnabled');
+    }
+  },
+
+  'setWhitelistPref': function(whitelist) {
+    if (whitelist !== undefined) {
+      SpecialPowers.setCharPref('dom.mozBrowserFramesWhitelist', whitelist);
+    }
+    else {
+      SpecialPowers.clearUserPref('dom.mozBrowserFramesWhitelist');
+    }
+  },
+
+  'addToWhitelist': function() {
+    var whitelist = browserFrameHelpers.getWhitelistPref();
+    whitelist += ',  http://' + window.location.host + ',  ';
+    browserFrameHelpers.setWhitelistPref(whitelist);
+  },
+
+  'restoreOriginalPrefs': function() {
+    browserFrameHelpers.setEnabledPref(browserFrameHelpers.origEnabledPref);
+    browserFrameHelpers.setWhitelistPref(browserFrameHelpers.origWhitelistPref);
+  },
+
+  'origEnabledPref': null,
+  'origWhitelistPref': null
+};
+
+browserFrameHelpers.origEnabledPref = browserFrameHelpers.getEnabledPref();
+browserFrameHelpers.origWhitelistPref = browserFrameHelpers.getWhitelistPref();
+
+addEventListener('unload', function() {
+  browserFrameHelpers.restoreOriginalPrefs();
+});
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_browserFrame1.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+  <title>Test for Bug 710231</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<!--
+  Test that an iframe without the |mozbrowser| attribute does not emit
+  mozbrowserX events.
+-->
+
+<iframe id='iframe' onload='iframeLoad()'></iframe>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  var iframe = document.getElementById('iframe');
+  iframe.addEventListener('mozbrowserloadstart', function() {
+    ok(false, 'Should not send mozbrowserloadstart event.');
+  });
+
+  iframe.src = 'http://example.com';
+}
+
+function iframeLoad() {
+  ok(true, 'Got iframe load event.');
+  SimpleTest.finish();
+}
+
+addEventListener('load', runTest());
+
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_browserFrame2.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+  <title>Test for Bug 710231</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserFrameHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<!--
+  Test that an iframe with the |mozbrowser| attribute does not emit
+  mozbrowserX events when they're globally pref'ed off.
+-->
+
+<iframe id='iframe' mozbrowser onload='iframeLoad()'></iframe>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  browserFrameHelpers.setEnabledPref(false);
+
+  var iframe = document.getElementById('iframe');
+  iframe.addEventListener('mozbrowserloadstart', function() {
+    ok(false, 'Should not send mozbrowserloadstart event.');
+  });
+
+  iframe.src = 'http://example.com';
+}
+
+function iframeLoad() {
+  ok(true, 'Got iframe load event.');
+  SimpleTest.finish();
+}
+
+addEventListener('load', runTest());
+
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_browserFrame3.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+  <title>Test for Bug 710231</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserFrameHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<!--
+  Test that an iframe with the |mozbrowser| attribute does not emit
+  mozbrowserX events when this page is not in the whitelist.
+-->
+
+<iframe id='iframe' mozbrowser onload='iframeLoad()'></iframe>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  browserFrameHelpers.setEnabledPref(true);
+  browserFrameHelpers.setWhitelistPref(' http://foobar.com');
+
+  var iframe = document.getElementById('iframe');
+  iframe.addEventListener('mozbrowserloadstart', function() {
+    ok(false, 'Should not send mozbrowserloadstart event.');
+  });
+
+  iframe.src = 'http://example.com';
+}
+
+function iframeLoad() {
+  ok(true, 'Got iframe load event.');
+  SimpleTest.finish();
+}
+
+addEventListener('load', runTest());
+
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_browserFrame4.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=710231
+-->
+<head>
+  <title>Test for Bug 710231</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserFrameHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=710231">Mozilla Bug 710231</a>
+
+<!--
+  Test that an iframe with the |mozbrowser| attribute emits
+  mozbrowserX events when this page is in the whitelist.
+-->
+
+<iframe id='iframe' mozbrowser></iframe>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+var seenLoadStart = false;
+var seenLoad = false;
+var seenLoadEnd = false;
+var seenLocationChange = false;
+
+function runTest() {
+  browserFrameHelpers.setEnabledPref(true);
+  browserFrameHelpers.addToWhitelist();
+
+  var iframe = document.getElementById('iframe');
+
+  iframe.addEventListener('mozbrowserloadstart', function() {
+    ok(!seenLoadStart, 'Just one loadstart event.');
+    seenLoadStart = true;
+    ok(!seenLoad, 'Got mozbrowserloadstart event before load.');
+    ok(!seenLoadEnd, 'Got mozbrowserloadstart before loadend.');
+    ok(!seenLocationChange, 'Got mozbrowserloadstart before locationchange.');
+  });
+
+  iframe.addEventListener('mozbrowserlocationchange', function(e) {
+    ok(!seenLocationChange, 'Just one locationchange event.');
+    seenLocationChange = true;
+    ok(seenLoadStart, 'Location change after load start.');
+    ok(!seenLoad, 'Location change before load.');
+    ok(!seenLoadEnd, 'Location change before load end.');
+  });
+
+  iframe.addEventListener('load', function() {
+    ok(!seenLoad, 'Just one load event.');
+    seenLoad = true;
+    ok(seenLoadStart, 'Load after loadstart.');
+    ok(seenLocationChange, 'Load after locationchange.');
+    ok(!seenLoadEnd, 'Load before loadend.');
+  });
+
+  iframe.addEventListener('mozbrowserloadend', function() {
+    ok(!seenLoadEnd, 'Just one load end event.');
+    seenLoadEnd = true;
+    ok(seenLoadStart, 'Load end after load start.');
+    ok(seenLocationChange, 'Load end after location change.');
+  });
+
+  iframe.src = 'http://example.com';
+  waitForAllCallbacks();
+}
+
+function waitForAllCallbacks() {
+  if (!seenLoadStart || !seenLoad || !seenLoadEnd || !seenLocationChange) {
+    SimpleTest.executeSoon(waitForAllCallbacks);
+    return;
+  }
+
+  SimpleTest.finish();
+}
+
+addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
+
+</script>
+
+</body>
+</html>
deleted file mode 100644
--- a/dom/tests/mochitest/general/test_getContentState.html
+++ /dev/null
@@ -1,144 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=708963
--->
-<head>
-  <title>Test for Bug 708963</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=708963">Mozilla Bug 708963</a>
-
-<script type="application/javascript;version=1.7">
-"use strict";
-
-function getEnabledPref() {
-  try {
-    return SpecialPowers.getBoolPref('dom.mozBrowserFramesEnabled');
-  }
-  catch(e) {
-    return undefined;
-  }
-}
-
-function getWhitelistPref() {
-  try {
-    return SpecialPowers.getCharPref('dom.mozBrowserFramesWhitelist');
-  }
-  catch(e) {
-    return undefined;
-  }
-}
-
-function setPrefs(enabled, whitelist) {
-  if (enabled !== undefined) {
-    SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', enabled);
-  }
-  else {
-    SpecialPowers.clearUserPref('dom.mozBrowserFramesEnabled');
-  }
-
-  if (whitelist !== undefined) {
-    SpecialPowers.setCharPref('dom.mozBrowserFramesWhitelist', whitelist);
-  }
-  else {
-    SpecialPowers.clearUserPref('dom.mozBrowserFramesWhitelist');
-  }
-}
-
-function getPrePath() {
-  return 'http://' + window.location.host;
-}
-
-function checkCannotQueryIframe(id) {
-  let iframe = document.getElementById(id);
-  try {
-    iframe.mozGetContentState('location', function() {
-      ok(false, 'Got callback, but should have failed.');
-    });
-    ok(false, 'Should have thrown exception.');
-  }
-  catch(e) {
-    ok(true, 'Got expected exception.');
-  }
-}
-
-function checkCannotQuery() {
-  checkCannotQueryIframe('queryable');
-  checkCannotQueryIframe('not-queryable');
-}
-
-let numCallbacksExpected = 0;
-let numCallbacksSeen = 0;
-function checkCanQuery() {
-  checkCannotQueryIframe('not-queryable');
-
-  let iframe = document.getElementById('queryable');
-  iframe.mozGetContentState('location', function(href) {
-    ok(true, 'Got callback, as expected.');
-    is(href, 'http://example.com/', "Callback value.");
-    numCallbacksSeen++;
-  });
-  numCallbacksExpected++;
-}
-
-const oldEnabled = getEnabledPref();
-const oldWhitelist = getWhitelistPref();
-
-function runTest() {
-  setPrefs(false, getPrePath());
-  checkCannotQuery();
-
-  setPrefs(true, '');
-  checkCannotQuery();
-
-  setPrefs(true, getPrePath());
-  checkCanQuery();
-
-  setPrefs(true, 'http://example.com  , ' +
-                 getPrePath().toUpperCase() + ',  ');
-  checkCanQuery();
-
-  // Spin if we haven't seen all the expected callbacks.
-  waitForAllExpectedCallbacks();
-}
-
-function waitForAllExpectedCallbacks() {
-  if (numCallbacksSeen < numCallbacksExpected) {
-    SimpleTest.executeSoon(waitForAllExpectedCallbacks);
-    return;
-  }
-
-  // Spin the event loop a few times to let any remaining pending callbacks
-  // fire.  (If we get any callbacks here, the test should fail.)
-  SimpleTest.executeSoon(function() {
-    SimpleTest.executeSoon(function() {
-      SimpleTest.executeSoon(function() {
-        setPrefs(oldEnabled, oldWhitelist);
-        SimpleTest.finish();
-      });
-    });
-  });
-}
-
-SimpleTest.waitForExplicitFinish();
-
-var numLoaded = 0;
-function iframeLoaded() {
-  numLoaded++;
-  if (numLoaded == 2) {
-    runTest();
-  }
-}
-
-</script>
-
-<iframe onload='iframeLoaded()' id='not-queryable' src='http://example.org'></iframe>
-<iframe onload='iframeLoaded()' mozbrowser id='queryable' src='http://example.com'></iframe>
-
-</body>
-</html>
-
-
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -64,22 +64,22 @@
 #endif
 
 #if defined(ANDROID)
 /* from widget */
 #if defined(MOZ_WIDGET_ANDROID)
 #include "AndroidBridge.h"
 #endif
 #include <android/log.h>
+#endif
+
 #define EGL_LIB "libEGL.so"
 #define GLES2_LIB "libGLESv2.so"
-#else
-#define EGL_LIB "libEGL.so.1"
-#define GLES2_LIB "libGLESv2.so.2"
-#endif
+#define EGL_LIB1 "libEGL.so.1"
+#define GLES2_LIB2 "libGLESv2.so.2"
 
 typedef void *EGLNativeDisplayType;
 typedef void *EGLNativePixmapType;
 typedef void *EGLNativeWindowType;
 
 #elif defined(XP_WIN)
 
 #include "mozilla/Preferences.h"
@@ -381,16 +381,21 @@ public:
 
             eglFile->Append(NS_LITERAL_STRING("libEGL.dll"));
             eglFile->Load(&mEGLLibrary);
         } while (false);
 #endif
 
         if (!mEGLLibrary) {
             mEGLLibrary = PR_LoadLibrary(EGL_LIB);
+#if defined(XP_UNIX)
+            if (!mEGLLibrary) {
+                mEGLLibrary = PR_LoadLibrary(EGL_LIB1);
+            }
+#endif
         }
 
         if (!mEGLLibrary) {
             NS_WARNING("Couldn't load EGL LIB.");
             return false;
         }
 
 #define SYMBOL(name) \
@@ -745,17 +750,21 @@ public:
 
     GLContextType GetContextType() {
         return ContextTypeEGL;
     }
 
     bool Init()
     {
         if (!OpenLibrary(GLES2_LIB)) {
-            NS_WARNING("Couldn't load EGL LIB.");
+#if defined(XP_UNIX)
+            if (!OpenLibrary(GLES2_LIB2)) {
+                NS_WARNING("Couldn't load EGL LIB.");
+            }
+#endif
             return false;
         }
 
         bool current = MakeCurrent();
         if (!current) {
             gfx::LogFailure(NS_LITERAL_CSTRING(
                 "Couldn't get device attachments for device."));
             return false;
--- a/gfx/skia/src/ports/SkFontHost_mac_coretext.cpp
+++ b/gfx/skia/src/ports/SkFontHost_mac_coretext.cpp
@@ -791,18 +791,18 @@ CGRGBPixel* Offscreen::getCG(const SkSca
     SkASSERT(rowBytesPtr);
     *rowBytesPtr = rowBytes;
     return image;
 }
 
 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const {
     CGSize vertOffset;
     CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffset, 1);
-    const SkPoint trans = {SkFloatToScalar(vertOffset.width),
-                           SkFloatToScalar(vertOffset.height)};
+    const SkPoint trans = {SkScalar(SkFloatToScalar(vertOffset.width)),
+                           SkScalar(SkFloatToScalar(vertOffset.height))};
     SkPoint floatOffset;
     fVerticalMatrix.mapPoints(&floatOffset, &trans, 1);
     if (!isSnowLeopard()) {
     // SnowLeopard fails to apply the font's matrix to the vertical metrics,
     // but Lion and Leopard do. The unit matrix describes the font's matrix at
     // point size 1. There may be some way to avoid mapping here by setting up
     // fVerticalMatrix differently, but this works for now.
         fUnitMatrix.mapPoints(&floatOffset, 1);
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -1011,16 +1011,28 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxC
     GetRoundOffsetsToPixels(aContext, &roundX, &roundY);
 
     PRInt32 appUnitsPerDevUnit = aShapedWord->AppUnitsPerDevUnit();
 
     // factor to convert 16.16 fixed-point pixels to app units
     // (only used if not rounding)
     double hb2appUnits = FixedToFloat(aShapedWord->AppUnitsPerDevUnit());
 
+    // Residual from rounding of previous advance, for use in rounding the
+    // subsequent offset or advance appropriately.  16.16 fixed-point
+    //
+    // When rounding, the goal is to make the distance between glyphs and
+    // their base glyph equal to the integral number of pixels closest to that
+    // suggested by that shaper.
+    // i.e. posInfo[n].x_advance - posInfo[n].x_offset + posInfo[n+1].x_offset
+    //
+    // The value of the residual is the part of the desired distance that has
+    // not been included in integer offsets.
+    hb_position_t x_residual = 0;
+
     // keep track of y-position to set glyph offsets if needed
     nscoord yPos = 0;
 
     const hb_glyph_position_t *posInfo = hb_buffer_get_glyph_positions(aBuffer);
 
     while (glyphStart < numGlyphs) {
 
         bool inOrder = true;
@@ -1111,70 +1123,89 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxC
         // (This may be done within harfbuzz eventually.)
         if (glyphsInClump == 1 && baseCharIndex + 1 == endCharIndex &&
             aShapedWord->FilterIfIgnorable(baseCharIndex)) {
             glyphStart = glyphEnd;
             charStart = charEnd;
             continue;
         }
 
-        // Check if it's a simple one-to-one mapping
+        hb_position_t x_offset = posInfo[glyphStart].x_offset;
         hb_position_t x_advance = posInfo[glyphStart].x_advance;
-        nscoord advance =
-            roundX ? appUnitsPerDevUnit * FixedToIntRound(x_advance)
-            : floor(hb2appUnits * x_advance + 0.5);
-
+        nscoord xOffset, advance;
+        if (roundX) {
+            xOffset =
+                appUnitsPerDevUnit * FixedToIntRound(x_offset + x_residual);
+            // Desired distance from the base glyph to the next reference point.
+            hb_position_t width = x_advance - x_offset;
+            int intWidth = FixedToIntRound(width);
+            x_residual = width - FloatToFixed(intWidth);
+            advance = appUnitsPerDevUnit * intWidth + xOffset;
+        } else {
+            xOffset = floor(hb2appUnits * x_offset + 0.5);
+            advance = floor(hb2appUnits * x_advance + 0.5);
+        }
+        // Check if it's a simple one-to-one mapping
         if (glyphsInClump == 1 &&
             gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
             gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
             aShapedWord->IsClusterStart(baseCharIndex) &&
-            posInfo[glyphStart].x_offset == 0 &&
+            xOffset == 0 &&
             posInfo[glyphStart].y_offset == 0 && yPos == 0)
         {
             gfxTextRun::CompressedGlyph g;
             aShapedWord->SetSimpleGlyph(baseCharIndex,
                                      g.SetSimpleGlyph(advance,
                                          ginfo[glyphStart].codepoint));
         } else {
             // collect all glyphs in a list to be assigned to the first char;
             // there must be at least one in the clump, and we already measured
             // its advance, hence the placement of the loop-exit test and the
             // measurement of the next glyph
             while (1) {
                 gfxTextRun::DetailedGlyph* details =
                     detailedGlyphs.AppendElement();
                 details->mGlyphID = ginfo[glyphStart].codepoint;
 
-                // Rounding offsets independently of advances on the assumption
-                // that clusters use offsets and rounding of offsets should
-                // not accumulate, and that advances are typically between
-                // clusters.
-                hb_position_t x_offset = posInfo[glyphStart].x_offset;
-                details->mXOffset =
-                    roundX ? appUnitsPerDevUnit * FixedToIntRound(x_offset)
-                    : floor(hb2appUnits * x_offset + 0.5);
+                details->mXOffset = xOffset;
+                details->mAdvance = advance;
+
                 hb_position_t y_offset = posInfo[glyphStart].y_offset;
                 details->mYOffset = yPos -
                     (roundY ? appUnitsPerDevUnit * FixedToIntRound(y_offset)
                      : floor(hb2appUnits * y_offset + 0.5));
 
-                details->mAdvance = advance;
                 hb_position_t y_advance = posInfo[glyphStart].y_advance;
                 if (y_advance != 0) {
                     yPos -=
                         roundY ? appUnitsPerDevUnit * FixedToIntRound(y_advance)
                         : floor(hb2appUnits * y_advance + 0.5);
                 }
                 if (++glyphStart >= glyphEnd) {
                     break;
                 }
+
+                x_offset = posInfo[glyphStart].x_offset;
                 x_advance = posInfo[glyphStart].x_advance;
-                advance =
-                    roundX ? appUnitsPerDevUnit * FixedToIntRound(x_advance)
-                    : floor(hb2appUnits * x_advance + 0.5);
+                if (roundX) {
+                    xOffset = appUnitsPerDevUnit *
+                        FixedToIntRound(x_offset + x_residual);
+                    // Desired distance to the next reference point.  The
+                    // residual is considered here, and includes the residual
+                    // from the base glyph offset and subsequent advances, so
+                    // that the distance from the base glyph is optimized
+                    // rather than the distance from combining marks.
+                    x_advance += x_residual;
+                    int intAdvance = FixedToIntRound(x_advance);
+                    x_residual = x_advance - FloatToFixed(intAdvance);
+                    advance = appUnitsPerDevUnit * intAdvance;
+                } else {
+                    xOffset = floor(hb2appUnits * x_offset + 0.5);
+                    advance = floor(hb2appUnits * x_advance + 0.5);
+                }
             }
 
             gfxTextRun::CompressedGlyph g;
             g.SetComplex(aShapedWord->IsClusterStart(baseCharIndex),
                          true, detailedGlyphs.Length());
             aShapedWord->SetGlyphs(baseCharIndex,
                                 g, detailedGlyphs.Elements());
 
--- a/image/build/nsImageModule.cpp
+++ b/image/build/nsImageModule.cpp
@@ -57,21 +57,21 @@
 
 #include "nsICOEncoder.h"
 #include "nsPNGEncoder.h"
 #include "nsJPEGEncoder.h"
 #include "nsBMPEncoder.h"
 
 // objects that just require generic constructors
 namespace mozilla {
-namespace imagelib {
+namespace image {
 NS_GENERIC_FACTORY_CONSTRUCTOR(RasterImage)
 }
 }
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(imgLoader, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(imgTools)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsICOEncoder)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGEncoder)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsPNGEncoder)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBMPEncoder)
@@ -131,17 +131,17 @@ imglib_Initialize()
   imgLoader::InitCache();
   return NS_OK;
 }
 
 static void
 imglib_Shutdown()
 {
   imgLoader::Shutdown();
-  mozilla::imagelib::DiscardTracker::Shutdown();
+  mozilla::image::DiscardTracker::Shutdown();
 }
 
 static const mozilla::Module kImageModule = {
   mozilla::Module::kVersion,
   kImageCIDs,
   kImageContracts,
   kImageCategories,
   NULL,
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -48,17 +48,17 @@
 #include "nsBMPDecoder.h"
 
 #include "nsIInputStream.h"
 #include "RasterImage.h"
 #include "imgIContainerObserver.h"
 #include "ImageLogging.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 #ifdef PR_LOGGING
 PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder");
 #endif
 
 // Convert from row (1..height) to absolute line (0..height-1)
 #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
 #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
@@ -770,10 +770,10 @@ void nsBMPDecoder::ProcessInfoHeader()
     mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
     mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
     mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
     mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
     mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
     mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -43,17 +43,17 @@
 
 #include "nsAutoPtr.h"
 #include "imgIDecoderObserver.h"
 #include "gfxColor.h"
 #include "Decoder.h"
 #include "BMPFileHeaders.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 class RasterImage;
 
 /**
  * Decoder for BMP-Files, as used by Windows and OS/2
  */
 class nsBMPDecoder : public Decoder
 {
@@ -158,14 +158,14 @@ inline void Set4BitPixel(PRUint32*& aDec
     SetPixel(aDecoded, idx, aColors);
     if (--aCount > 0) {
         idx = aData & 0xF;
         SetPixel(aDecoded, idx, aColors);
         --aCount;
     }
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 
 #endif
 
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -80,17 +80,17 @@ mailing address.
 #include "imgIContainerObserver.h"
 #include "RasterImage.h"
 
 #include "gfxColor.h"
 #include "gfxPlatform.h"
 #include "qcms.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 /*
  * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
  *
  * Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
  * as each GIF block (except colormaps) can never be bigger than 256 bytes.
  * Colormaps are directly copied in the resp. global_colormap or the local_colormap of the PAL image frame
  * So a fixed buffer in gif_struct is good enough.
@@ -1099,10 +1099,10 @@ done:
 
 Telemetry::ID
 nsGIFDecoder2::SpeedHistogram()
 {
   return Telemetry::IMAGE_DECODE_SPEED_GIF;
 }
 
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/decoders/nsGIFDecoder2.h
+++ b/image/decoders/nsGIFDecoder2.h
@@ -43,17 +43,17 @@
 
 #include "nsCOMPtr.h"
 #include "Decoder.h"
 #include "imgIDecoderObserver.h"
 
 #include "GIF2.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 class RasterImage;
 
 //////////////////////////////////////////////////////////////////////
 // nsGIFDecoder2 Definition
 
 class nsGIFDecoder2 : public Decoder
 {
 public:
@@ -97,12 +97,12 @@ private:
   PRUint8 mLastFlushedPass;
   PRUint8 mColorMask;        // Apply this to the pixel to keep within colormap
   bool mGIFOpen;
   bool mSawTransparency;
 
   gif_struct mGIFStruct;
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -51,17 +51,17 @@
 #include "nsIComponentManager.h"
 #include "RasterImage.h"
 #include "imgIContainerObserver.h"
 
 #include "nsIProperties.h"
 #include "nsISupportsPrimitives.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 #define ICONCOUNTOFFSET 4
 #define DIRENTRYOFFSET 6
 #define BITMAPINFOSIZE 40
 #define PREFICONSIZE 16
 
 // ----------------------------------------
 // Actual Data Processing
@@ -606,10 +606,10 @@ nsICODecoder::ProcessDirEntry(IconDirEnt
   aTarget.mBitCount = LITTLE_TO_NATIVE16(aTarget.mBitCount);
   memcpy(&aTarget.mBytesInRes, mDirEntryArray + 8, sizeof(aTarget.mBytesInRes));
   aTarget.mBytesInRes = LITTLE_TO_NATIVE32(aTarget.mBytesInRes);
   memcpy(&aTarget.mImageOffset, mDirEntryArray + 12, 
          sizeof(aTarget.mImageOffset));
   aTarget.mImageOffset = LITTLE_TO_NATIVE32(aTarget.mImageOffset);
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -45,17 +45,17 @@
 #include "nsAutoPtr.h"
 #include "Decoder.h"
 #include "imgIDecoderObserver.h"
 #include "nsBMPDecoder.h"
 #include "nsPNGDecoder.h"
 #include "ICOFileHeaders.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 class RasterImage;
 
 class nsICODecoder : public Decoder
 {
 public:
 
   nsICODecoder(RasterImage &aImage, imgIDecoderObserver* aObserver);
@@ -118,12 +118,12 @@ private:
   // Holds the potential bytes for a bitmap information header
   char mBIHraw[40];
   // Stores whether or not the icon file we are processing has type 1 (icon)
   bool mIsCursor;
   // Stores whether or not the contained resource is a PNG
   bool mIsPNG;
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif
--- a/image/decoders/nsIconDecoder.cpp
+++ b/image/decoders/nsIconDecoder.cpp
@@ -43,17 +43,17 @@
 #include "RasterImage.h"
 #include "imgIContainerObserver.h"
 #include "nspr.h"
 #include "nsRect.h"
 
 #include "ImageErrors.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 nsIconDecoder::nsIconDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
  : Decoder(aImage, aObserver),
    mWidth(-1),
    mHeight(-1),
    mPixBytesRead(0),
    mPixBytesTotal(0),
    mImageData(nsnull),
@@ -160,10 +160,10 @@ nsIconDecoder::WriteInternal(const char 
         // Consume all excess data silently
         aCount = 0;
 
         break;
     }
   }
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/decoders/nsIconDecoder.h
+++ b/image/decoders/nsIconDecoder.h
@@ -43,17 +43,17 @@
 
 #include "Decoder.h"
 
 #include "nsCOMPtr.h"
 
 #include "imgIDecoderObserver.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 class RasterImage;
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 // The icon decoder is a decoder specifically tailored for loading icons 
 // from the OS. We've defined our own little format to represent these icons
 // and this decoder takes that format and converts it into 24-bit RGB with alpha channel
 // support. It was modeled a bit off the PPM decoder.
 //
@@ -89,12 +89,12 @@ public:
 
 enum {
   iconStateStart      = 0,
   iconStateHaveHeight = 1,
   iconStateReadPixels = 2,
   iconStateFinished   = 3
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif // nsIconDecoder_h__
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -69,17 +69,17 @@ METHODDEF(void)
 ycc_rgb_convert_argb (j_decompress_ptr cinfo,
                  JSAMPIMAGE input_buf, JDIMENSION input_row,
                  JSAMPARRAY output_buf, int num_rows);
 }
 
 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 #if defined(PR_LOGGING)
 PRLogModuleInfo *gJPEGlog = PR_NewLogModule("JPEGDecoder");
 static PRLogModuleInfo *gJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
 #else
 #define gJPEGlog
 #define gJPEGDecoderAccountingLog
 #endif
@@ -885,17 +885,17 @@ term_source (j_decompress_ptr jd)
   // recover from.
   NS_ABORT_IF_FALSE(decoder->mState != JPEG_ERROR,
                     "Calling term_source on a JPEG with mState == JPEG_ERROR!");
 
   // Notify using a helper method to get around protectedness issues.
   decoder->NotifyDone();
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 
 /**************** YCbCr -> Cairo's RGB24/ARGB32 conversion: most common case **************/
 
 /*
  * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
  * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
--- a/image/decoders/nsJPEGDecoder.h
+++ b/image/decoders/nsJPEGDecoder.h
@@ -58,17 +58,17 @@
 
 extern "C" {
 #include "jpeglib.h"
 }
 
 #include <setjmp.h>
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 typedef struct {
     struct jpeg_error_mgr pub;  /* "public" fields for IJG library*/
     jmp_buf setjmp_buffer;      /* For handling catastropic errors */
 } decoder_error_mgr;
 
 typedef enum {
     JPEG_HEADER,                          /* Reading JFIF headers */
@@ -123,12 +123,12 @@ public:
   qcms_profile *mInProfile;
   qcms_transform *mTransform;
 
   bool mReading;
 
   PRUint32 mCMSMode;
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif // nsJPEGDecoder_h__
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -56,17 +56,17 @@
 #include "nsColor.h"
 
 #include "nspr.h"
 #include "png.h"
 
 #include "gfxPlatform.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo *gPNGLog = PR_NewLogModule("PNGDecoder");
 static PRLogModuleInfo *gPNGDecoderAccountingLog =
                         PR_NewLogModule("PNGDecoderAccounting");
 #endif
 
 /* limit image dimensions (bug #251381) */
@@ -882,10 +882,10 @@ nsPNGDecoder::warning_callback(png_struc
 
 Telemetry::ID
 nsPNGDecoder::SpeedHistogram()
 {
   return Telemetry::IMAGE_DECODE_SPEED_PNG;
 }
 
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -48,17 +48,17 @@
 
 #include "nsCOMPtr.h"
 
 #include "png.h"
 
 #include "qcms.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 class RasterImage;
 
 class nsPNGDecoder : public Decoder
 {
 public:
   nsPNGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver);
   virtual ~nsPNGDecoder();
 
@@ -136,12 +136,12 @@ public:
   static void PNGAPI warning_callback(png_structp png_ptr,
                                       png_const_charp warning_msg);
 
   // This is defined in the PNG spec as an invariant. We use it to
   // do manual validation without libpng.
   static const PRUint8 pngSignatureBytes[];
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif // nsPNGDecoder_h__
--- a/image/encoders/bmp/nsBMPEncoder.cpp
+++ b/image/encoders/bmp/nsBMPEncoder.cpp
@@ -540,17 +540,17 @@ nsBMPEncoder::InitInfoHeader(PRUint32 aB
   mBMPInfoHeader.xppm = 0;
   mBMPInfoHeader.yppm = 0;
 }
 
 // Encodes the BMP file header mBMPFileHeader
 void 
 nsBMPEncoder::EncodeFileHeader() 
 {  
-  mozilla::imagelib::BMPFILEHEADER littleEndianBFH = mBMPFileHeader;
+  mozilla::image::BMPFILEHEADER littleEndianBFH = mBMPFileHeader;
   littleEndianBFH.filesize = NATIVE32_TO_LITTLE(littleEndianBFH.filesize);
   littleEndianBFH.reserved = NATIVE32_TO_LITTLE(littleEndianBFH.reserved);
   littleEndianBFH.dataoffset= NATIVE32_TO_LITTLE(littleEndianBFH.dataoffset);
   littleEndianBFH.bihsize = NATIVE32_TO_LITTLE(littleEndianBFH.bihsize);
 
   memcpy(mImageBufferCurr, &littleEndianBFH.signature, 
          sizeof(littleEndianBFH.signature));
   mImageBufferCurr += sizeof(littleEndianBFH.signature);
@@ -567,17 +567,17 @@ nsBMPEncoder::EncodeFileHeader()
          sizeof(littleEndianBFH.bihsize));
   mImageBufferCurr += sizeof(littleEndianBFH.bihsize);
 }
 
 // Encodes the BMP infor header mBMPInfoHeader
 void 
 nsBMPEncoder::EncodeInfoHeader()
 {
-  mozilla::imagelib::BMPINFOHEADER littleEndianmBIH = mBMPInfoHeader;
+  mozilla::image::BMPINFOHEADER littleEndianmBIH = mBMPInfoHeader;
   littleEndianmBIH.width =  NATIVE32_TO_LITTLE(littleEndianmBIH.width);
   littleEndianmBIH.height = NATIVE32_TO_LITTLE(littleEndianmBIH.height); 
   littleEndianmBIH.planes = NATIVE16_TO_LITTLE(littleEndianmBIH.planes);
   littleEndianmBIH.bpp = NATIVE16_TO_LITTLE(littleEndianmBIH.bpp);
   littleEndianmBIH.compression = NATIVE32_TO_LITTLE(
                                  littleEndianmBIH.compression);
   littleEndianmBIH.image_size = NATIVE32_TO_LITTLE(
                                 littleEndianmBIH.image_size);
--- a/image/encoders/bmp/nsBMPEncoder.h
+++ b/image/encoders/bmp/nsBMPEncoder.h
@@ -93,18 +93,18 @@ protected:
   // Obtains the current offset filled up to for the image buffer
   inline PRInt32 GetCurrentImageBufferOffset()
   {
     return static_cast<PRInt32>(mImageBufferCurr - mImageBufferStart);
   }
 
   // These headers will always contain endian independent stuff 
   // They store the BMP headers which will be encoded
-  mozilla::imagelib::BMPFILEHEADER mBMPFileHeader;
-  mozilla::imagelib::BMPINFOHEADER mBMPInfoHeader;
+  mozilla::image::BMPFILEHEADER mBMPFileHeader;
+  mozilla::image::BMPINFOHEADER mBMPInfoHeader;
 
   // Keeps track of the start of the image buffer
   PRUint8* mImageBufferStart;
   // Keeps track of the current position in the image buffer
   PRUint8* mImageBufferCurr;
   // Keeps track of the image buffer size
   PRUint32 mImageBufferSize;
   // Keeps track of the number of bytes in the image buffer which are read
--- a/image/encoders/ico/nsICOEncoder.cpp
+++ b/image/encoders/ico/nsICOEncoder.cpp
@@ -41,17 +41,17 @@
 #include "nsPNGEncoder.h"
 #include "nsICOEncoder.h"
 #include "prmem.h"
 #include "prprf.h"
 #include "nsString.h"
 #include "nsStreamUtils.h"
 
 using namespace mozilla;
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 
 NS_IMPL_THREADSAFE_ISUPPORTS3(nsICOEncoder, imgIEncoder, nsIInputStream, nsIAsyncInputStream)
 
 nsICOEncoder::nsICOEncoder() : mImageBufferStart(nsnull),
                                mImageBufferCurr(0),
                                mImageBufferSize(0), 
                                mImageBufferReadPoint(0), 
                                mFinished(false),
--- a/image/encoders/ico/nsICOEncoder.h
+++ b/image/encoders/ico/nsICOEncoder.h
@@ -103,18 +103,18 @@ protected:
 
   // Holds either a PNG or a BMP depending on the encoding options specified
   // or if no encoding options specified will use the default (PNG)
   nsCOMPtr<imgIEncoder> mContainedEncoder;
 
   // These headers will always contain endian independent stuff.
   // Don't trust the width and height of mICODirEntry directly,
   // instead use the accessors GetRealWidth() and GetRealHeight().
-  mozilla::imagelib::IconFileHeader mICOFileHeader;
-  mozilla::imagelib::IconDirEntry mICODirEntry;
+  mozilla::image::IconFileHeader mICOFileHeader;
+  mozilla::image::IconDirEntry mICODirEntry;
 
   // Keeps track of the start of the image buffer
   PRUint8* mImageBufferStart;
   // Keeps track of the current position in the image buffer
   PRUint8* mImageBufferCurr;
   // Keeps track of the image buffer size
   PRUint32 mImageBufferSize;
   // Keeps track of the number of bytes in the image buffer which are read
--- a/image/src/BMPFileHeaders.h
+++ b/image/src/BMPFileHeaders.h
@@ -34,17 +34,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef MOZILLA_IMAGELIB_BMPHEADERS_H_
 #define MOZILLA_IMAGELIB_BMPHEADERS_H_
 
 namespace mozilla {
-  namespace imagelib {
+  namespace image {
 
     struct BMPFILEHEADER {
       char signature[2]; // String "BM"
       PRUint32 filesize;
       PRInt32 reserved; // Zero
       PRUint32 dataoffset; // Offset to raster data
 
       PRUint32 bihsize;
@@ -92,17 +92,17 @@ namespace mozilla {
       PRUint8 redLeftShift;
       PRUint8 redRightShift;
       PRUint8 greenLeftShift;
       PRUint8 greenRightShift;
       PRUint8 blueLeftShift;
       PRUint8 blueRightShift;
     };
 
-  } // namespace imagelib
+  } // namespace image
 } // namespace mozilla
 
 #define BITFIELD_LENGTH 12 // Length of the bitfields structure in the bmp file
 #define USE_RGB
 
 // BMPINFOHEADER.compression defines
 #ifndef BI_RGB
 #define BI_RGB 0
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -37,17 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "Decoder.h"
 #include "nsIServiceManager.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 Decoder::Decoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
   : mImage(aImage)
   , mObserver(aObserver)
   , mDecodeFlags(0)
   , mDecodeDone(false)
   , mDataError(false)
   , mFrameCount(0)
@@ -321,10 +321,10 @@ Decoder::PostDecoderError(nsresult aFail
 
   mFailCode = aFailureCode;
 
   // XXXbholley - we should report the image URI here, but imgContainer
   // needs to know its URI first
   NS_WARNING("Image decoding error - This is probably a bug!");
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -39,17 +39,17 @@
 #ifndef MOZILLA_IMAGELIB_DECODER_H_
 #define MOZILLA_IMAGELIB_DECODER_H_
 
 #include "RasterImage.h"
 
 #include "imgIDecoderObserver.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 class Decoder
 {
 public:
 
   Decoder(RasterImage& aImage, imgIDecoderObserver* aObserver);
   virtual ~Decoder();
 
@@ -216,12 +216,12 @@ private:
   nsresult mFailCode;
 
   bool mInitialized;
   bool mSizeDecode;
   bool mInFrame;
   bool mIsAnimated;
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif // MOZILLA_IMAGELIB_DECODER_H_
--- a/image/src/DiscardTracker.cpp
+++ b/image/src/DiscardTracker.cpp
@@ -37,17 +37,17 @@
 
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include "RasterImage.h"
 #include "DiscardTracker.h"
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 static bool sInitialized = false;
 static bool sTimerOn = false;
 static PRUint32 sMinDiscardTimeoutMs = 10000; /* Default if pref unreadable. */
 static nsITimer *sTimer = nsnull;
 static struct DiscardTrackerNode sHead, sSentinel, sTail;
 
 /*
@@ -284,10 +284,10 @@ DiscardTracker::TimerCallback(nsITimer *
   Reset(&sSentinel);
 
   // If there's nothing in front of the sentinel, the next callback
   // is guaranteed to be a no-op. Disable the timer as an optimization.
   if (sSentinel.prev == &sHead)
     TimerOff();
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/src/DiscardTracker.h
+++ b/image/src/DiscardTracker.h
@@ -38,17 +38,17 @@
 #ifndef mozilla_imagelib_DiscardTracker_h_
 #define mozilla_imagelib_DiscardTracker_h_
 
 #define DISCARD_TIMEOUT_PREF "image.mem.min_discard_timeout_ms"
 
 class nsITimer;
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 class RasterImage;
 
 // Struct to make a RasterImage insertable into the tracker list. This
 // is embedded within each RasterImage object, and we do 'this->curr = this'
 // on RasterImage construction. Thus, a RasterImage must always call
 // DiscardTracker::Remove() in its destructor to avoid having the tracker
 // point to bogus memory.
 struct DiscardTrackerNode
@@ -79,12 +79,12 @@ class DiscardTracker
     static void DiscardAll();
   private:
     static nsresult Initialize();
     static nsresult TimerOn();
     static void TimerOff();
     static void TimerCallback(nsITimer *aTimer, void *aClosure);
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif /* mozilla_imagelib_DiscardTracker_h_ */
--- a/image/src/ICOFileHeaders.h
+++ b/image/src/ICOFileHeaders.h
@@ -35,17 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 
 #ifndef MOZILLA_IMAGELIB_ICOHEADERS_H_
 #define MOZILLA_IMAGELIB_ICOHEADERS_H_
 
 namespace mozilla {
-  namespace imagelib {
+  namespace image {
 
     #define ICONFILEHEADERSIZE 6
     #define ICODIRENTRYSIZE 16
     #define PNGSIGNATURESIZE 8
     #define BMPFILEHEADERSIZE 14
 
     struct IconFileHeader
     {
@@ -68,12 +68,12 @@ namespace mozilla {
         PRUint16 mBitCount; // ICO
         PRUint16 mYHotspot; // CUR
       };
       PRUint32  mBytesInRes;
       PRUint32  mImageOffset;
     };
 
 
-  } // namespace imagelib
+  } // namespace image
 } // namespace mozilla
 
 #endif
--- a/image/src/Image.cpp
+++ b/image/src/Image.cpp
@@ -33,17 +33,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Image.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 // Constructor
 Image::Image(imgStatusTracker* aStatusTracker) :
   mInnerWindowId(0),
   mAnimationConsumers(0),
   mAnimationMode(kNormalAnimMode),
   mInitialized(false),
   mAnimating(false),
@@ -169,10 +169,10 @@ Image::EvaluateAnimation()
     nsresult rv = StartAnimation();
     mAnimating = NS_SUCCEEDED(rv);
   } else if (mAnimating && !ShouldAnimate()) {
     StopAnimation();
     mAnimating = false;
   }
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/src/Image.h
+++ b/image/src/Image.h
@@ -38,17 +38,17 @@
 #ifndef MOZILLA_IMAGELIB_IMAGE_H_
 #define MOZILLA_IMAGELIB_IMAGE_H_
 
 #include "imgIContainer.h"
 #include "imgStatusTracker.h"
 #include "prtypes.h"
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 class Image : public imgIContainer
 {
 public:
   // From NS_DECL_IMGICONTAINER:
   NS_SCRIPTABLE NS_IMETHOD GetAnimationMode(PRUint16 *aAnimationMode);
   NS_SCRIPTABLE NS_IMETHOD SetAnimationMode(PRUint16 aAnimationMode);
 
@@ -158,12 +158,12 @@ protected:
    * Extended by child classes, if they have additional
    * conditions for being able to animate
    */
   virtual bool ShouldAnimate() {
     return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode;
   }
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif // MOZILLA_IMAGELIB_IMAGE_H_
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -68,17 +68,17 @@
 #include "gfxContext.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/StdInt.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 
 using namespace mozilla;
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 using namespace mozilla::layers;
 
 // a mask for flags that will affect the decoding
 #define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
 #define DECODE_FLAGS_DEFAULT 0
 
 /* Accounting for compressed data */
 #if defined(PR_LOGGING)
@@ -169,17 +169,17 @@ DiscardingEnabled()
 
     enabled = (PR_GetEnv("MOZ_DISABLE_IMAGE_DISCARD") == nsnull);
   }
 
   return enabled;
 }
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 #ifndef DEBUG
 NS_IMPL_ISUPPORTS3(RasterImage, imgIContainer, nsIProperties,
                    nsISupportsWeakReference)
 #else
 NS_IMPL_ISUPPORTS4(RasterImage, imgIContainer, nsIProperties,
                    imgIContainerDebug, nsISupportsWeakReference)
 #endif
@@ -2949,10 +2949,10 @@ RasterImage::GetFramesNotified(PRUint32 
   NS_ENSURE_ARG_POINTER(aFramesNotified);
 
   *aFramesNotified = mFramesNotified;
 
   return NS_OK;
 }
 #endif
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -157,17 +157,17 @@ class nsIInputStream;
  * in Init().
  */
 
 namespace mozilla {
 namespace layers {
 class LayerManager;
 class ImageContainer;
 }
-namespace imagelib {
+namespace image {
 
 class imgDecodeWorker;
 class Decoder;
 
 class RasterImage : public Image
                   , public nsIProperties
                   , public nsSupportsWeakReference
 #ifdef DEBUG
@@ -632,12 +632,12 @@ class imgDecodeRequestor : public nsRunn
         con->RequestDecode();
       return NS_OK;
     }
 
   private:
     nsWeakPtr mContainer;
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif /* mozilla_imagelib_RasterImage_h_ */
--- a/image/src/SVGDocumentWrapper.cpp
+++ b/image/src/SVGDocumentWrapper.cpp
@@ -61,17 +61,17 @@
 #include "gfxRect.h"
 #include "nsSVGSVGElement.h"
 #include "nsSVGLength2.h"
 #include "nsSVGEffects.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 NS_IMPL_ISUPPORTS4(SVGDocumentWrapper,
                    nsIStreamListener,
                    nsIRequestObserver,
                    nsIObserver,
                    nsISupportsWeakReference)
 
 SVGDocumentWrapper::SVGDocumentWrapper()
@@ -459,10 +459,10 @@ SVGDocumentWrapper::GetRootSVGElem()
   Element* rootElem = mViewer->GetDocument()->GetRootElement();
   if (!rootElem || !rootElem->IsSVG(nsGkAtoms::svg)) {
     return nsnull;
   }
 
   return static_cast<nsSVGSVGElement*>(rootElem);
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/src/SVGDocumentWrapper.h
+++ b/image/src/SVGDocumentWrapper.h
@@ -57,17 +57,17 @@ class nsIFrame;
 struct nsIntSize;
 class nsSVGSVGElement;
 
 #define SVG_MIMETYPE     "image/svg+xml"
 #define OBSERVER_SVC_CID "@mozilla.org/observer-service;1"
 
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 
 class SVGDocumentWrapper MOZ_FINAL : public nsIStreamListener,
                                      public nsIObserver,
                                      nsSupportsWeakReference
 {
 public:
   SVGDocumentWrapper();
   ~SVGDocumentWrapper();
@@ -182,12 +182,12 @@ private:
 
   nsCOMPtr<nsIContentViewer>  mViewer;
   nsCOMPtr<nsILoadGroup>      mLoadGroup;
   nsCOMPtr<nsIStreamListener> mListener;
   bool                        mIgnoreInvalidation;
   bool                        mRegisteredForXPCOMShutdown;
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif // mozilla_imagelib_SVGDocumentWrapper_h_
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -54,17 +54,17 @@
 #include "gfxDrawable.h"
 #include "gfxUtils.h"
 #include "nsSVGSVGElement.h"
 
 namespace mozilla {
 
 using namespace dom;
 
-namespace imagelib {
+namespace image {
 
 // Helper-class: SVGRootRenderingObserver
 class SVGRootRenderingObserver : public nsSVGRenderingObserver {
 public:
   SVGRootRenderingObserver(SVGDocumentWrapper* aDocWrapper,
                            VectorImage*        aVectorImage)
     : nsSVGRenderingObserver(),
       mDocWrapper(aDocWrapper),
@@ -742,10 +742,10 @@ VectorImage::InvalidateObserver()
   }
 
   nsCOMPtr<imgIDecoderObserver> decoderObs(do_QueryReferent(mObserver));
   if (decoderObs) {
     decoderObs->OnStopFrame(nsnull, imgIContainer::FRAME_CURRENT);
   }
 }
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
--- a/image/src/VectorImage.h
+++ b/image/src/VectorImage.h
@@ -46,17 +46,17 @@
 
 class imgIDecoderObserver;
 
 namespace mozilla {
 namespace layers {
 class LayerManager;
 class ImageContainer;
 }
-namespace imagelib {
+namespace image {
 
 class SVGDocumentWrapper;
 class SVGRootRenderingObserver;
 
 class VectorImage : public Image,
                     public nsIStreamListener
 {
 public:
@@ -127,12 +127,12 @@ private:
   bool           mIsFullyLoaded:1;        // Has OnStopRequest been called?
   bool           mIsDrawing:1;            // Are we currently drawing?
   bool           mHaveAnimations:1;       // Is our SVG content SMIL-animated?
                                           // (Only set after mIsFullyLoaded.)
   bool           mHaveRestrictedRegion:1; // Are we a restricted-region clone
                                           // created via ExtractFrame?
 };
 
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 #endif // mozilla_imagelib_VectorImage_h_
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -91,17 +91,17 @@
 // until this point, we have an evil hack:
 #include "nsIHttpChannelInternal.h"  
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 
 #include "nsContentUtils.h"
 
 using namespace mozilla;
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 
 #if defined(DEBUG_pavlov) || defined(DEBUG_timeless)
 #include "nsISimpleEnumerator.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsXPIDLString.h"
 #include "nsComponentManagerUtils.h"
 
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -82,17 +82,17 @@
 #include "mozilla/Preferences.h"
 
 #include "DiscardTracker.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 
 #define SVG_MIMETYPE "image/svg+xml"
 
 using namespace mozilla;
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 
 static bool gInitializedPrefCaches = false;
 static bool gDecodeOnDraw = false;
 static bool gDiscardable = false;
 
 static void
 InitPrefCaches()
 {
--- a/image/src/imgRequest.h
+++ b/image/src/imgRequest.h
@@ -66,19 +66,19 @@
 class imgCacheValidator;
 
 class imgRequestProxy;
 class imgCacheEntry;
 class imgMemoryReporter;
 class imgRequestNotifyRunnable;
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 class Image;
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 class imgRequest : public imgIDecoderObserver,
                    public nsIStreamListener,
                    public nsSupportsWeakReference,
                    public nsIChannelEventSink,
                    public nsIInterfaceRequestor,
                    public nsIAsyncVerifyRedirectCallback
@@ -222,17 +222,17 @@ private:
   // The URI of the resource we ended up loading after all redirects, etc.
   nsCOMPtr<nsIURI> mCurrentURI;
   // The principal of the document which loaded this image. Used when validating for CORS.
   nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
   // The principal of this image.
   nsCOMPtr<nsIPrincipal> mPrincipal;
   // Status-tracker -- transferred to mImage, when it gets instantiated
   nsAutoPtr<imgStatusTracker> mStatusTracker;
-  nsRefPtr<mozilla::imagelib::Image> mImage;
+  nsRefPtr<mozilla::image::Image> mImage;
   nsCOMPtr<nsIProperties> mProperties;
   nsCOMPtr<nsISupports> mSecurityInfo;
   nsCOMPtr<nsIChannel> mChannel;
   nsCOMPtr<nsIInterfaceRequestor> mPrevChannelSink;
 
   nsTObserverArray<imgRequestProxy*> mObservers;
 
   nsCOMPtr<nsITimedChannel> mTimedChannel;
--- a/image/src/imgRequestProxy.cpp
+++ b/image/src/imgRequestProxy.cpp
@@ -50,17 +50,17 @@
 #include "nsCRT.h"
 
 #include "Image.h"
 #include "ImageErrors.h"
 #include "ImageLogging.h"
 
 #include "nspr.h"
 
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 
 NS_IMPL_ADDREF(imgRequestProxy)
 NS_IMPL_RELEASE(imgRequestProxy)
 
 NS_INTERFACE_MAP_BEGIN(imgRequestProxy)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, imgIRequest)
   NS_INTERFACE_MAP_ENTRY(imgIRequest)
   NS_INTERFACE_MAP_ENTRY(nsIRequest)
--- a/image/src/imgRequestProxy.h
+++ b/image/src/imgRequestProxy.h
@@ -62,19 +62,19 @@
      0x11b2,                                         \
     {0x8f, 0x65, 0x9c, 0x46, 0x2e, 0xe2, 0xbc, 0x95} \
 }
 
 class imgRequestNotifyRunnable;
 class imgStatusNotifyRunnable;
 
 namespace mozilla {
-namespace imagelib {
+namespace image {
 class Image;
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 class imgRequestProxy : public imgIRequest, 
                         public nsISupportsPriority, 
                         public nsISecurityInfoProvider,
                         public nsITimedChannel
 {
 public:
@@ -86,17 +86,17 @@ public:
   // nsITimedChannel declared below
 
   imgRequestProxy();
   virtual ~imgRequestProxy();
 
   // Callers to Init or ChangeOwner are required to call NotifyListener after
   // (although not immediately after) doing so.
   nsresult Init(imgRequest *request, nsILoadGroup *aLoadGroup,
-                mozilla::imagelib::Image* aImage,
+                mozilla::image::Image* aImage,
                 nsIURI* aURI, imgIDecoderObserver *aObserver);
 
   nsresult ChangeOwner(imgRequest *aNewOwner); // this will change mOwner.  Do not call this if the previous
                                                // owner has already sent notifications out!
 
   void AddToLoadGroup();
   void RemoveFromLoadGroup(bool releaseLoadGroup);
 
@@ -125,17 +125,17 @@ public:
   }
   void SetNotificationsDeferred(bool aDeferNotifications)
   {
     mDeferNotifications = aDeferNotifications;
   }
 
   // Setter for our |mImage| pointer, for imgRequest to use, once it
   // instantiates an Image.
-  void SetImage(mozilla::imagelib::Image* aImage);
+  void SetImage(mozilla::image::Image* aImage);
 
   // Removes all animation consumers that were created with
   // IncrementAnimationConsumers. This is necessary since we need
   // to do it before the proxy itself is destroyed. See
   // imgRequest::RemoveProxy
   void ClearAnimationConsumers();
 
 protected:
@@ -223,17 +223,17 @@ private:
   // means that imgRequest::mObservers will not have any stale pointers in it.
   nsRefPtr<imgRequest> mOwner;
 
   // The URI of our request.
   nsCOMPtr<nsIURI> mURI;
 
   // The image we represent. Is null until data has been received, and is then
   // set by imgRequest.
-  nsRefPtr<mozilla::imagelib::Image> mImage;
+  nsRefPtr<mozilla::image::Image> mImage;
 
   // Our principal. Is null until data has been received from the channel, and
   // is then set by imgRequest.
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   // mListener is only promised to be a weak ref (see imgILoader.idl),
   // but we actually keep a strong ref to it until we've seen our
   // first OnStopRequest.
--- a/image/src/imgStatusTracker.cpp
+++ b/image/src/imgStatusTracker.cpp
@@ -41,17 +41,17 @@
 
 #include "imgRequest.h"
 #include "imgIContainer.h"
 #include "imgRequestProxy.h"
 #include "Image.h"
 #include "ImageLogging.h"
 #include "RasterImage.h"
 
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 
 static nsresult
 GetResultFromImageStatus(PRUint32 aStatus)
 {
   if (aStatus & imgIRequest::STATUS_ERROR)
     return NS_IMAGELIB_ERROR_FAILURE;
   if (aStatus & imgIRequest::STATUS_LOAD_COMPLETE)
     return NS_IMAGELIB_SUCCESS_LOAD_FINISHED;
--- a/image/src/imgStatusTracker.h
+++ b/image/src/imgStatusTracker.h
@@ -42,19 +42,19 @@
 
 class imgIContainer;
 class imgRequest;
 class imgRequestProxy;
 class imgStatusNotifyRunnable;
 class imgRequestNotifyRunnable;
 struct nsIntRect;
 namespace mozilla {
-namespace imagelib {
+namespace image {
 class Image;
-} // namespace imagelib
+} // namespace image
 } // namespace mozilla
 
 
 #include "nsCOMPtr.h"
 #include "nsIRunnable.h"
 #include "prtypes.h"
 #include "nscore.h"
 
@@ -79,24 +79,24 @@ enum {
  */
 
 class imgStatusTracker
 {
 public:
   // aImage is the image that this status tracker will pass to the
   // imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
   // alive as long as this instance is, because we hold a weak reference to it.
-  imgStatusTracker(mozilla::imagelib::Image* aImage);
+  imgStatusTracker(mozilla::image::Image* aImage);
   imgStatusTracker(const imgStatusTracker& aOther);
 
   // Image-setter, for imgStatusTrackers created by imgRequest::Init, which
   // are created before their Image is created.  This method should only
   // be called once, and only on an imgStatusTracker that was initialized
   // without an image.
-  void SetImage(mozilla::imagelib::Image* aImage);
+  void SetImage(mozilla::image::Image* aImage);
 
   // Schedule an asynchronous "replaying" of all the notifications that would
   // have to happen to put us in the current state.
   // We will also take note of any notifications that happen between the time
   // Notify() is called and when we call SyncNotify on |proxy|, and replay them
   // as well.
   void Notify(imgRequest* request, imgRequestProxy* proxy);
 
@@ -177,15 +177,15 @@ public:
 private:
   friend class imgStatusNotifyRunnable;
   friend class imgRequestNotifyRunnable;
 
   nsCOMPtr<nsIRunnable> mRequestRunnable;
 
   // A weak pointer to the Image, because it owns us, and we
   // can't create a cycle.
-  mozilla::imagelib::Image* mImage;
+  mozilla::image::Image* mImage;
   PRUint32 mState;
   nsresult mImageStatus;
   bool mHadLastPart;
 };
 
 #endif
--- a/image/src/imgTools.cpp
+++ b/image/src/imgTools.cpp
@@ -48,17 +48,17 @@
 #include "nsStringStream.h"
 #include "nsComponentManagerUtils.h"
 #include "nsWeakReference.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsStreamUtils.h"
 #include "nsNetUtil.h"
 #include "RasterImage.h"
 
-using namespace mozilla::imagelib;
+using namespace mozilla::image;
 
 /* ========== imgITools implementation ========== */
 
 
 
 NS_IMPL_ISUPPORTS1(imgTools, imgITools)
 
 imgTools::imgTools()
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -344,17 +344,22 @@ class Vector : private AllocPolicy
     bool empty() const {
         return mLength == 0;
     }
 
     size_t capacity() const {
         return mCapacity;
     }
 
-    T *begin() const {
+    T *begin() {
+        JS_ASSERT(!entered);
+        return mBegin;
+    }
+
+    const T *begin() const {
         JS_ASSERT(!entered);
         return mBegin;
     }
 
     T *end() {
         JS_ASSERT(!entered);
         return mBegin + mLength;
     }
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -166,16 +166,17 @@ CPPSRCS		= \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
 		SemanticAnalysis.cpp \
 		TokenStream.cpp \
 		LifoAlloc.cpp \
+		MapObject.cpp \
 		MemoryMetrics.cpp \
 		RegExpObject.cpp \
 		RegExpStatics.cpp \
 		RegExp.cpp \
 		Statistics.cpp \
 		Unicode.cpp \
 		$(NULL)
 
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/MapObject.cpp
@@ -0,0 +1,407 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey JavaScript engine.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Jason Orendorff <jorendorff@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "builtin/MapObject.h"
+
+#include "jscntxt.h"
+#include "jsgcmark.h"
+#include "jsobj.h"
+
+#include "vm/GlobalObject.h"
+#include "vm/Stack.h"
+
+#include "jsobjinlines.h"
+
+using namespace js;
+
+static JSObject *
+InitClass(JSContext *cx, GlobalObject *global, Class *clasp, JSProtoKey key, Native construct,
+          JSFunctionSpec *methods)
+{
+    JSObject *proto = global->createBlankPrototype(cx, clasp);
+    if (!proto)
+        return NULL;
+    proto->setPrivate(NULL);
+
+    JSAtom *atom = cx->runtime->atomState.classAtoms[key];
+    JSFunction *ctor = global->createConstructor(cx, construct, clasp, atom, 0);
+    if (!ctor ||
+        !LinkConstructorAndPrototype(cx, ctor, proto) ||
+        !DefinePropertiesAndBrand(cx, proto, NULL, methods) ||
+        !DefineConstructorAndPrototype(cx, global, key, ctor, proto))
+    {
+        return NULL;
+    }
+    return proto;
+}
+
+
+/*** HashableValue *******************************************************************************/
+
+bool
+HashableValue::setValue(JSContext *cx, const Value &v)
+{
+    if (v.isString() && v.toString()->isRope()) {
+        /* Flatten this rope so that equals() is infallible. */
+        JSString *str = v.toString()->ensureLinear(cx);
+        if (!str)
+            return false;
+        value = StringValue(str);
+    } else if (v.isDouble()) {
+        jsdouble d = v.toDouble();
+        int32_t i;
+        if (JSDOUBLE_IS_INT32(d, &i)) {
+            /* Normalize int32-valued doubles to int32 for faster hashing and testing. */
+            value = Int32Value(i);
+        } else {
+#ifdef DEBUG
+            /* All NaN values are the same. The bit-pattern must reflect this. */
+            jsval_layout a, b;
+            a.asDouble = d;
+            b.asDouble = JS_CANONICALIZE_NAN(d);
+            JS_ASSERT(a.asBits == b.asBits);
+#endif
+            value = v;
+        }
+    } else {
+        value = v;
+    }
+
+    JS_ASSERT(value.isUndefined() || value.isNull() || value.isBoolean() ||
+              value.isNumber() || value.isString() || value.isObject());
+    return true;
+}
+
+HashNumber
+HashableValue::hash() const
+{
+    /*
+     * HashableValue::setValue normalizes values so that the SameValue relation
+     * on HashableValues is the same as the == relationship on
+     * value.data.asBits, except for strings.
+     */
+    if (value.isString()) {
+        JSLinearString &s = value.toString()->asLinear();
+        return HashChars(s.chars(), s.length());
+    }
+
+    /* Having dispensed with strings, we can just hash asBits. */
+    uint64_t u = value.asRawBits();
+    return HashNumber((u >> 3) ^ (u >> (32 + 3)) ^ (u << (32 - 3)));
+}
+
+bool
+HashableValue::equals(const HashableValue &other) const
+{
+    /* Two HashableValues are equal if they have equal bits or they're equal strings. */
+    bool b = (value.asRawBits() == other.value.asRawBits()) ||
+              (value.isString() &&
+               other.value.isString() &&
+               EqualStrings(&value.toString()->asLinear(),
+                            &other.value.toString()->asLinear()));
+
+#ifdef DEBUG
+    JSBool same;
+    JS_ASSERT(SameValue(NULL, value, other.value, &same));
+    JS_ASSERT(same == b);
+#endif
+    return b;
+}
+
+
+/*** Map *****************************************************************************************/
+
+Class MapObject::class_ = {
+    "Map",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
+    JS_PropertyStub,         /* addProperty */
+    JS_PropertyStub,         /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    finalize,
+    NULL,                    /* reserved0   */
+    NULL,                    /* checkAccess */
+    NULL,                    /* call        */
+    NULL,                    /* construct   */
+    NULL,                    /* xdrObject   */
+    NULL,                    /* hasInstance */
+    mark
+};
+
+JSFunctionSpec MapObject::methods[] = {
+    JS_FN("get", get, 1, 0),
+    JS_FN("has", has, 1, 0),
+    JS_FN("set", set, 2, 0),
+    JS_FN("delete", delete_, 1, 0),
+    JS_FS_END
+};
+
+JSObject *
+MapObject::initClass(JSContext *cx, JSObject *obj)
+{
+    return InitClass(cx, &obj->asGlobal(), &class_, JSProto_Map, construct, methods);
+}
+
+void
+MapObject::mark(JSTracer *trc, JSObject *obj)
+{
+    MapObject *mapobj = static_cast<MapObject *>(obj);
+    if (ValueMap *map = mapobj->getData()) {
+        for (ValueMap::Range r = map->all(); !r.empty(); r.popFront()) {
+            gc::MarkValue(trc, r.front().key, "key");
+            gc::MarkValue(trc, r.front().value, "value");
+        }
+    }
+}
+
+void
+MapObject::finalize(JSContext *cx, JSObject *obj)
+{
+    MapObject *mapobj = static_cast<MapObject *>(obj);
+    if (ValueMap *map = mapobj->getData())
+        cx->delete_(map);
+}
+
+JSBool
+MapObject::construct(JSContext *cx, uintN argc, Value *vp)
+{
+    JSObject *obj = NewBuiltinClassInstance(cx, &class_);
+    if (!obj)
+        return false;
+
+    ValueMap *map = cx->new_<ValueMap>(cx->runtime);
+    if (!map || !map->init())
+        return false;
+    obj->setPrivate(map);
+
+    CallArgsFromVp(argc, vp).rval().setObject(*obj);
+    return true;
+}
+
+#define UNPACK_THIS(T, native, cx, argc, vp, args, data)                      \
+    CallArgs args = CallArgsFromVp(argc, vp);                                 \
+    if (!args.thisv().isObject() ||                                           \
+        !args.thisv().toObject().hasClass(&T::class_))                        \
+    {                                                                         \
+        return js::HandleNonGenericMethodClassMismatch(cx, args, native,      \
+                                                       &T::class_);           \
+    }                                                                         \
+    if (!args.thisv().toObject().getPrivate()) {                              \
+        ReportIncompatibleMethod(cx, args, &T::class_);                       \
+        return false;                                                         \
+    }                                                                         \
+    T::Data &data = *static_cast<T &>(args.thisv().toObject()).getData();     \
+    (void) data
+
+#define THIS_MAP(native, cx, argc, vp, args, map)                             \
+    UNPACK_THIS(MapObject, native, cx, argc, vp, args, map)
+
+#define ARG0_KEY(cx, args, key)                                               \
+    HashableValue key;                                                        \
+    if (args.length() > 0 && !key.setValue(cx, args[0]))                      \
+        return false
+
+JSBool
+MapObject::get(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_MAP(get, cx, argc, vp, args, map);
+    ARG0_KEY(cx, args, key);
+
+    if (ValueMap::Ptr p = map.lookup(key))
+        args.rval() = p->value;
+    else
+        args.rval().setUndefined();
+    return true;
+}
+
+JSBool
+MapObject::has(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_MAP(has, cx, argc, vp, args, map);
+    ARG0_KEY(cx, args, key);
+    args.rval().setBoolean(map.lookup(key));
+    return true;
+}
+
+JSBool
+MapObject::set(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_MAP(set, cx, argc, vp, args, map);
+    ARG0_KEY(cx, args, key);
+    map.put(key, args.length() > 1 ? args[1] : UndefinedValue());
+    args.rval().setUndefined();
+    return true;
+}
+
+JSBool
+MapObject::delete_(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_MAP(delete_, cx, argc, vp, args, map);
+    ARG0_KEY(cx, args, key);
+    ValueMap::Ptr p = map.lookup(key);
+    bool found = p.found();
+    if (found)
+        map.remove(p);
+    args.rval().setBoolean(found);
+    return true;
+}
+
+JSObject *
+js_InitMapClass(JSContext *cx, JSObject *obj)
+{
+    return MapObject::initClass(cx, obj);
+}
+
+
+/*** Set *****************************************************************************************/
+
+Class SetObject::class_ = {
+    "Set",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
+    JS_PropertyStub,         /* addProperty */
+    JS_PropertyStub,         /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    finalize,
+    NULL,                    /* reserved0   */
+    NULL,                    /* checkAccess */
+    NULL,                    /* call        */
+    NULL,                    /* construct   */
+    NULL,                    /* xdrObject   */
+    NULL,                    /* hasInstance */
+    mark
+};
+
+JSFunctionSpec SetObject::methods[] = {
+    JS_FN("has", has, 1, 0),
+    JS_FN("add", add, 1, 0),
+    JS_FN("delete", delete_, 1, 0),
+    JS_FS_END
+};
+
+JSObject *
+SetObject::initClass(JSContext *cx, JSObject *obj)
+{
+    return InitClass(cx, &obj->asGlobal(), &class_, JSProto_Set, construct, methods);
+}
+
+void
+SetObject::mark(JSTracer *trc, JSObject *obj)
+{
+    SetObject *setobj = static_cast<SetObject *>(obj);
+    if (ValueSet *set = setobj->getData()) {
+        for (ValueSet::Range r = set->all(); !r.empty(); r.popFront())
+            gc::MarkValue(trc, r.front(), "key");
+    }
+}
+
+void
+SetObject::finalize(JSContext *cx, JSObject *obj)
+{
+    SetObject *setobj = static_cast<SetObject *>(obj);
+    if (ValueSet *set = setobj->getData())
+        cx->delete_(set);
+}
+
+JSBool
+SetObject::construct(JSContext *cx, uintN argc, Value *vp)
+{
+    JSObject *obj = NewBuiltinClassInstance(cx, &class_);
+    if (!obj)
+        return false;
+
+    ValueSet *set = cx->new_<ValueSet>(cx->runtime);
+    if (!set || !set->init())
+        return false;
+    obj->setPrivate(set);
+
+    CallArgsFromVp(argc, vp).rval().setObject(*obj);
+    return true;
+}
+
+#define THIS_SET(native, cx, argc, vp, args, set)                             \
+    UNPACK_THIS(SetObject, native, cx, argc, vp, args, set)
+
+JSBool
+SetObject::has(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_SET(has, cx, argc, vp, args, set);
+    ARG0_KEY(cx, args, key);
+    args.rval().setBoolean(set.has(key));
+    return true;
+}
+
+JSBool
+SetObject::add(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_SET(add, cx, argc, vp, args, set);
+    ARG0_KEY(cx, args, key);
+    if (!set.put(key))
+        return false;
+    args.rval().setUndefined();
+    return true;
+}
+
+JSBool
+SetObject::delete_(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_SET(delete_, cx, argc, vp, args, set);
+    ARG0_KEY(cx, args, key);
+    ValueSet::Ptr p = set.lookup(key);
+    bool found = p.found();
+    if (found)
+        set.remove(p);
+    args.rval().setBoolean(found);
+    return true;
+}
+
+JSObject *
+js_InitSetClass(JSContext *cx, JSObject *obj)
+{
+    return SetObject::initClass(cx, obj);
+} 
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/MapObject.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SpiderMonkey JavaScript engine.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Jason Orendorff <jorendorff@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MapObject_h__
+#define MapObject_h__
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsobj.h"
+
+#include "js/HashTable.h"
+
+namespace js {
+
+/*
+ * Comparing two ropes for equality can fail. The js::HashTable template
+ * requires infallible hash() and match() operations. Therefore we require
+ * all values to be converted to hashable form before being used as a key
+ * in a Map or Set object.
+ *
+ * All values except ropes are hashable as-is.
+ */
+class HashableValue {
+    HeapValue value;
+
+  public:
+    struct Hasher {
+        typedef HashableValue Lookup;
+        static HashNumber hash(const Lookup &v) { return v.hash(); }
+        static bool match(const HashableValue &k, const Lookup &l) { return k.equals(l); }
+    };
+
+    HashableValue() : value(UndefinedValue()) {}
+
+    operator const HeapValue &() const { return value; }
+    bool setValue(JSContext *cx, const Value &v);
+    HashNumber hash() const;
+    bool equals(const HashableValue &other) const;
+};
+
+typedef HashMap<HashableValue, HeapValue, HashableValue::Hasher, RuntimeAllocPolicy> ValueMap;
+typedef HashSet<HashableValue, HashableValue::Hasher, RuntimeAllocPolicy> ValueSet;
+
+class MapObject : public JSObject {
+  public:
+    static JSObject *initClass(JSContext *cx, JSObject *obj);
+    static Class class_;
+  private:
+    typedef ValueMap Data;
+    static JSFunctionSpec methods[];
+    ValueMap *getData() { return static_cast<ValueMap *>(getPrivate()); }
+    static void mark(JSTracer *trc, JSObject *obj);
+    static void finalize(JSContext *cx, JSObject *obj);
+    static JSBool construct(JSContext *cx, uintN argc, Value *vp);
+    static JSBool get(JSContext *cx, uintN argc, Value *vp);
+    static JSBool has(JSContext *cx, uintN argc, Value *vp);
+    static JSBool set(JSContext *cx, uintN argc, Value *vp);
+    static JSBool delete_(JSContext *cx, uintN argc, Value *vp);
+};
+
+class SetObject : public JSObject {
+  public:
+    static JSObject *initClass(JSContext *cx, JSObject *obj);
+    static Class class_;
+  private:
+    typedef ValueSet Data;
+    static JSFunctionSpec methods[];
+    ValueSet *getData() { return static_cast<ValueSet *>(getPrivate()); }
+    static void mark(JSTracer *trc, JSObject *obj);
+    static void finalize(JSContext *cx, JSObject *obj);
+    static JSBool construct(JSContext *cx, uintN argc, Value *vp);
+    static JSBool has(JSContext *cx, uintN argc, Value *vp);
+    static JSBool add(JSContext *cx, uintN argc, Value *vp);
+    static JSBool delete_(JSContext *cx, uintN argc, Value *vp);
+};
+
+} /* namespace js */
+
+extern JSObject *
+js_InitMapClass(JSContext *cx, JSObject *obj);
+
+extern JSObject *
+js_InitSetClass(JSContext *cx, JSObject *obj);
+
+#endif  /* MapObject_h__ */
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -773,18 +773,18 @@ OPTIMIZE_JARS_CMD = $(PYTHON) $(call cor
 CREATE_PRECOMPLETE_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/createprecomplete.py)
 
 EXPAND_LIBS = $(PYTHON) -I$(DEPTH)/config $(topsrcdir)/config/expandlibs.py
 EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist -- $(MKSHLIB)
+EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
+EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
--- a/js/src/config/expandlibs_exec.py
+++ b/js/src/config/expandlibs_exec.py
@@ -43,16 +43,20 @@ With the --extract argument (useful for 
 from static libraries (or use those listed in library descriptors directly).
 
 With the --uselist argument (useful for e.g. $(CC)), it replaces all object
 files with a list file. This can be used to avoid limitations in the length
 of a command line. The kind of list file format used depends on the
 EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
 or 'linkerscript' for GNU ld linker scripts.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
+
+With the --reorder argument, followed by a file name, it will reorder the
+object files from the command line according to the order given in the file.
+Implies --extract.
 '''
 from __future__ import with_statement
 import sys
 import os
 from expandlibs import ExpandArgs, relativize
 import expandlibs_config as conf
 from optparse import OptionParser
 import subprocess
@@ -120,30 +124,51 @@ class ExpandArgsMore(ExpandArgs):
         self.tmp.append(tmp)
         f = os.fdopen(fd, "w")
         f.writelines(content)
         f.close()
         idx = self.index(objs[0])
         newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
         self[0:] = newlist
 
+    def reorder(self, order_list):
+        '''Given a list of file names without OBJ_SUFFIX, rearrange self
+        so that the object file names it contains are ordered according to
+        that list.
+        '''
+        objs = [o for o in self if o.endswith(conf.OBJ_SUFFIX)]
+        if not objs: return
+        idx = self.index(objs[0])
+        # Keep everything before the first object, then the ordered objects,
+        # then any other objects, then any non-objects after the first object
+        objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
+        self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
+                   [o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
+                   [x for x in self[idx:] if not x.endswith(conf.OBJ_SUFFIX)]
+
+
 def main():
     parser = OptionParser()
     parser.add_option("--extract", action="store_true", dest="extract",
         help="when a library has no descriptor file, extract it first, when possible")
     parser.add_option("--uselist", action="store_true", dest="uselist",
         help="use a list file for objects when executing a command")
     parser.add_option("--verbose", action="store_true", dest="verbose",
         help="display executed command and temporary files content")
+    parser.add_option("--reorder", dest="reorder",
+        help="reorder the objects according to the given list", metavar="FILE")
 
     (options, args) = parser.parse_args()
 
     with ExpandArgsMore(args) as args:
-        if options.extract:
+        if options.extract or options.reorder:
             args.extract()
+        if options.reorder:
+            with open(options.reorder) as file:
+                args.reorder([l.strip() for l in file.readlines()])
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print >>sys.stderr, "Executing: " + " ".join(args)
             for tmp in [f for f in args.tmp if os.path.isfile(f)]:
                 print >>sys.stderr, tmp + ":"
                 with open(tmp) as file:
--- a/js/src/ds/Sort.h
+++ b/js/src/ds/Sort.h
@@ -100,17 +100,17 @@ MergeArrayRuns(T *dst, const T *src, siz
 /*
  * Sort the array using the merge sort algorithm. The scratch should point to
  * a temporary storage that can hold nelems elements.
  *
  * The comparator must provide the () operator with the following signature:
  *
  *     bool operator()(const T& a, const T& a, bool *lessOrEqualp);
  *
- * It should return true on success and sets lessOrEqualp to the result of
+ * It should return true on success and set *lessOrEqualp to the result of
  * a <= b operation. If it returns false, the sort terminates immediately with
  * the false result. In this case the content of the array and scratch is
  * arbitrary.
  */
 template<typename T, typename Comparator>
 bool
 MergeSort(T *array, size_t nelems, T *scratch, Comparator c)
 {
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -316,37 +316,42 @@ class HeapValue
      * the barrier. If you already know the compartment, it's faster to pass it
      * in.
      */
     inline void set(JSCompartment *comp, const Value &v);
 
     const Value &get() const { return value; }
     operator const Value &() const { return value; }
 
-    bool isMarkable() const { return value.isMarkable(); }
-    bool isMagic(JSWhyMagic why) const { return value.isMagic(why); }
     bool isUndefined() const { return value.isUndefined(); }
-    bool isObject() const { return value.isObject(); }
-    bool isGCThing() const { return value.isGCThing(); }
+    bool isNull() const { return value.isNull(); }
+    bool isBoolean() const { return value.isBoolean(); }
     bool isTrue() const { return value.isTrue(); }
     bool isFalse() const { return value.isFalse(); }
+    bool isNumber() const { return value.isNumber(); }
     bool isInt32() const { return value.isInt32(); }
-    bool isNull() const { return value.isNull(); }
+    bool isString() const { return value.isString(); }
+    bool isObject() const { return value.isObject(); }
+    bool isMagic(JSWhyMagic why) const { return value.isMagic(why); }
+    bool isGCThing() const { return value.isGCThing(); }
+    bool isMarkable() const { return value.isMarkable(); }
 
+    bool toBoolean() const { return value.toBoolean(); }
+    double toNumber() const { return value.toNumber(); }
+    int32_t toInt32() const { return value.toInt32(); }
+    double toDouble() const { return value.toDouble(); }
+    JSString *toString() const { return value.toString(); }
     JSObject &toObject() const { return value.toObject(); }
     JSObject *toObjectOrNull() const { return value.toObjectOrNull(); }
     void *toGCThing() const { return value.toGCThing(); }
-    double toDouble() const { return value.toDouble(); }
-    int32_t toInt32() const { return value.toInt32(); }
-    JSString *toString() const { return value.toString(); }
-    bool toBoolean() const { return value.toBoolean(); }
-    double toNumber() const { return value.toNumber(); }
 
     JSGCTraceKind gcKind() const { return value.gcKind(); }
 
+    uint64_t asRawBits() const { return value.asRawBits(); }
+
 #ifdef DEBUG
     JSWhyMagic whyMagic() const { return value.whyMagic(); }
 #endif
 
     static inline void writeBarrierPre(const Value &v);
     static inline void writeBarrierPost(const Value &v, void *addr);
 
     static inline void writeBarrierPre(JSCompartment *comp, const Value &v);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/lib/referencesVia.js
@@ -0,0 +1,26 @@
+function referencesVia(from, edge, to) {
+    if (typeof findReferences !== 'function')
+        return true;
+
+    edge = "edge: " + edge;
+    var edges = findReferences(to);
+    if (edge in edges && edges[edge].indexOf(from) != -1)
+        return true;
+
+    // Be nice: make it easy to fix if the edge name has just changed.
+    var alternatives = [];
+    for (var e in edges) {
+        if (edges[e].indexOf(from) != -1)
+            alternatives.push(e);
+    }
+    if (alternatives.length == 0) {
+        print("referent not referred to by referrer after all");
+    } else {
+        print("referent is not referenced via: " + uneval(edge));
+        print("but it is referenced via:       " + uneval(alternatives));
+    }
+    print("all incoming edges, from any object:");
+    for (var e in edges)
+        print(e);
+    return false;
+}
--- a/js/src/jit-test/tests/basic/testCrossCompartmentTransparency.js
+++ b/js/src/jit-test/tests/basic/testCrossCompartmentTransparency.js
@@ -77,16 +77,23 @@ test("new String('one')", function(s) St
 test("new RegExp('1')", function(r) RegExp.prototype.toString.call(r));
 test("new RegExp('1')", function(r) RegExp.prototype.exec.call(r, '1').toString());
 test("new RegExp('1')", function(r) RegExp.prototype.test.call(r, '1'));
 test("new RegExp('1')", function(r) RegExp.prototype.compile.call(r, '1').toString());
 test("new WeakMap()", function(w) WeakMap.prototype.has.call(w, {}));
 test("new WeakMap()", function(w) WeakMap.prototype.get.call(w, {}));
 test("new WeakMap()", function(w) WeakMap.prototype.delete.call(w, {}));
 test("new WeakMap()", function(w) WeakMap.prototype.set.call(w, {}));
+test("new Map()", function(w) Map.prototype.has.call(w, {}));
+test("new Map()", function(w) Map.prototype.get.call(w, {}));
+test("new Map()", function(w) Map.prototype.delete.call(w, {}));
+test("new Map()", function(w) Map.prototype.set.call(w, {}));
+test("new Set()", function(w) Set.prototype.has.call(w, {}));
+test("new Set()", function(w) Set.prototype.add.call(w, {}));
+test("new Set()", function(w) Set.prototype.delete.call(w, {}));
 
 test("new Int8Array(1)", function(a) Int8Array.prototype.subarray.call(a).toString());
 test("new Uint8Array(1)", function(a) Uint8Array.prototype.subarray.call(a).toString());
 test("new Int16Array(1)", function(a) Int16Array.prototype.subarray.call(a).toString());
 test("new Uint16Array(1)", function(a) Uint16Array.prototype.subarray.call(a).toString());
 test("new Int32Array(1)", function(a) Int32Array.prototype.subarray.call(a).toString());
 test("new Uint32Array(1)", function(a) Uint32Array.prototype.subarray.call(a).toString());
 test("new Float32Array(1)", function(a) Float32Array.prototype.subarray.call(a).toString());
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-delete.js
@@ -0,0 +1,18 @@
+// Map.prototype.delete works whether the key is present or not.
+
+var m = new Map;
+var key = {};
+
+// when the map is new
+assertEq(m.delete(key), false);
+assertEq(m.has(key), false);
+
+// when the key is present
+assertEq(m.set(key, 'x'), undefined);
+assertEq(m.delete(key), true);
+assertEq(m.has(key), false);
+assertEq(m.get(key), undefined);
+
+// when the key has already been deleted
+assertEq(m.delete(key), false);
+assertEq(m.has(key), false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-gc-1.js
@@ -0,0 +1,16 @@
+// Check marking through the keys of a Map.
+
+load(libdir + "referencesVia.js");
+
+var m = new Map;
+for (var i = 0; i < 20; i++) {
+    var n = new Map;
+    n.set(m, i);
+    assertEq(referencesVia(n, 'key', m), true);
+    m = n;
+}
+
+gc();
+gc();
+
+// TODO: walk the chain using for-of to make sure everything is still there
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-gc-2.js
@@ -0,0 +1,14 @@
+// Check marking through the values of a Map.
+
+load(libdir + "referencesVia.js");
+
+var m = new Map;
+for (var i = 0; i < 20; i++) {
+    var n = new Map;
+    n.set(i, m);
+    assertEq(referencesVia(n, 'value', m), true);
+    m = n;
+}
+
+gc();
+gc();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-get.js
@@ -0,0 +1,41 @@
+// Map.prototype.get and .has basically work
+var m = new Map;
+
+function rope() {
+    var s = "s";
+    for (var i = 0; i < 16; i++)
+        s += s;
+    return s;
+}
+
+var keys = [undefined, null, true, false,
+            0, 1, 65535, 65536, 2147483647, 2147483648, 4294967295, 4294967296,
+            -1, -65536, -2147483648,
+            0.5, Math.sqrt(81), Math.PI,
+            Number.MAX_VALUE, -Number.MAX_VALUE, Number.MIN_VALUE, -Number.MIN_VALUE,
+            -0, NaN, Infinity, -Infinity,
+            "", "\0", "a", "ab", "abcdefg", rope(),
+            {}, [], /a*b/, Object.prototype, Object];
+
+for (var i = 0; i < keys.length; i++) {
+    // without being set
+    var key = keys[i];
+    assertEq(m.has(key), false);
+    assertEq(m.get(key), undefined);
+
+    // after being set
+    var v = {};
+    assertEq(m.set(key, v), undefined);
+    assertEq(m.has(key), true);
+    assertEq(m.get(key), v);
+
+    // after being deleted
+    assertEq(m.delete(key), true);
+    assertEq(m.has(key), false);
+    assertEq(m.get(key), undefined);
+
+    m.set(key, v);
+}
+
+for (var i = 0; i < keys.length; i++)
+    assertEq(m.has(keys[i]), true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-scale.js
@@ -0,0 +1,8 @@
+// Maps can hold at least 64K values.
+
+var N = 1 << 16;
+var m = new Map;
+for (var i = 0; i < N; i++)
+    assertEq(m.set(i, i), undefined);
+for (var i = 0; i < N; i++)
+    assertEq(m.get(i), i);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-set-undefined.js
@@ -0,0 +1,15 @@
+// Setting a Map key to undefined, or a missing argument, isn't the same as deleting it.
+
+var m = new Map;
+m.set(42, undefined);
+assertEq(m.has(42), true);
+assertEq(m.get(42), undefined);
+
+m.set(42, "wrong");
+m.set(42);
+assertEq(m.has(42), true);
+assertEq(m.get(42), undefined);
+
+m.set();
+assertEq(m.has(undefined), true);
+assertEq(m.get(undefined), undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-surfaces-1.js
@@ -0,0 +1,33 @@
+// Map surfaces
+
+var desc = Object.getOwnPropertyDescriptor(this, "Map");
+assertEq(desc.enumerable, false);
+assertEq(desc.configurable, true);
+assertEq(desc.writable, true);
+
+assertEq(typeof Map, 'function');
+assertEq(Object.keys(Map).length, 0);
+assertEq(Map.length, 0);
+assertEq(Map.name, "Map");
+
+assertEq(Object.getPrototypeOf(Map.prototype), Object.prototype);
+assertEq(Object.prototype.toString.call(Map.prototype), "[object Map]");
+assertEq(Object.prototype.toString.call(new Map), "[object Map]");
+assertEq(Object.prototype.toString.call(Map()), "[object Map]");
+assertEq(Object.keys(Map.prototype).join(), "");
+assertEq(Map.prototype.constructor, Map);
+
+function checkMethod(name, arity) { 
+    var desc = Object.getOwnPropertyDescriptor(Map.prototype, name);
+    assertEq(desc.enumerable, false);
+    assertEq(desc.configurable, true);
+    assertEq(desc.writable, true);
+    assertEq(typeof desc.value, 'function');
+    assertEq(desc.value.name, name);
+    assertEq(desc.value.length, arity);
+}
+
+checkMethod("get", 1);
+checkMethod("has", 1);
+checkMethod("set", 2);
+checkMethod("delete", 1);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-surfaces-2.js
@@ -0,0 +1,23 @@
+// Map methods throw when passed a this-value that isn't a Map.
+
+load(libdir + "asserts.js");
+
+function testcase(obj, fn) {
+    assertEq(typeof fn, "function");
+    var args = Array.slice(arguments, 2);
+    assertThrowsInstanceOf(function () { fn.apply(obj, args); }, TypeError);
+}
+
+function test(obj) {
+    testcase(obj, Map.prototype.get, "x");
+    testcase(obj, Map.prototype.has, "x");
+    testcase(obj, Map.prototype.set, "x", 1);
+    testcase(obj, Map.prototype.delete, "x");
+}
+
+test(Map.prototype);
+test(Object.create(new Map));
+test(new Set());
+test({});
+test(null);
+test(undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Map-surfaces-3.js
@@ -0,0 +1,14 @@
+// Map methods work when arguments are omitted.
+
+var m = new Map;
+assertEq(m.has(), false);
+assertEq(m.get(), undefined);
+assertEq(m.delete(), false);
+assertEq(m.has(), false);
+assertEq(m.get(), undefined);
+assertEq(m.set(), undefined);
+assertEq(m.has(), true);
+assertEq(m.get(), undefined);
+assertEq(m.delete(), true);
+assertEq(m.has(), false);
+assertEq(m.get(), undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Set-gc-1.js
@@ -0,0 +1,16 @@
+// Check marking through the elements of a Set.
+
+load(libdir + "referencesVia.js");
+
+var s = new Set;
+for (var i = 0; i < 20; i++) {
+    var t = new Set;
+    t.add(s);
+    assertEq(referencesVia(t, 'key', s), true);
+    s = t;
+}
+
+gc();
+gc();
+
+// TODO: walk the chain and make sure it's still intact
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Set-scale.js
@@ -0,0 +1,8 @@
+// Sets can hold at least 64K values.
+
+var N = 1 << 16;
+var s = new Set;
+for (var i = 0; i < N; i++)
+    assertEq(s.add(i), undefined);
+for (var i = 0; i < N; i++)
+    assertEq(s.has(i), true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Set-surfaces-1.js
@@ -0,0 +1,32 @@
+// Set surfaces
+
+var desc = Object.getOwnPropertyDescriptor(this, "Set");
+assertEq(desc.enumerable, false);
+assertEq(desc.configurable, true);
+assertEq(desc.writable, true);
+
+assertEq(typeof Set, 'function');
+assertEq(Object.keys(Set).length, 0);
+assertEq(Set.length, 0);
+assertEq(Set.name, "Set");
+
+assertEq(Object.getPrototypeOf(Set.prototype), Object.prototype);
+assertEq(Object.prototype.toString.call(Set.prototype), "[object Set]");
+assertEq(Object.prototype.toString.call(new Set), "[object Set]");
+assertEq(Object.prototype.toString.call(Set()), "[object Set]");
+assertEq(Object.keys(Set.prototype).join(), "");
+assertEq(Set.prototype.constructor, Set);
+
+function checkMethod(name, arity) { 
+    var desc = Object.getOwnPropertyDescriptor(Set.prototype, name);
+    assertEq(desc.enumerable, false);
+    assertEq(desc.configurable, true);
+    assertEq(desc.writable, true);
+    assertEq(typeof desc.value, 'function');
+    assertEq(desc.value.name, name);
+    assertEq(desc.value.length, arity);
+}
+
+checkMethod("has", 1);
+checkMethod("add", 1);
+checkMethod("delete", 1);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Set-surfaces-2.js
@@ -0,0 +1,22 @@
+// Set methods throw when passed a this-value that isn't a Set.
+
+load(libdir + "asserts.js");
+
+function testcase(obj, fn) {
+    assertEq(typeof fn, "function");
+    var args = Array.slice(arguments, 2);
+    assertThrowsInstanceOf(function () { fn.apply(obj, args); }, TypeError);
+}
+
+function test(obj) {
+    testcase(obj, Set.prototype.has, 12);
+    testcase(obj, Set.prototype.add, 12);
+    testcase(obj, Set.prototype.delete, 12);
+}
+
+test(Set.prototype);
+test(Object.create(new Set));
+test(new Map());
+test({});
+test(null);
+test(undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/Set-surfaces-3.js
@@ -0,0 +1,10 @@
+// Set methods work when arguments are omitted.
+
+var s = new Set;
+assertEq(s.has(), false);
+assertEq(s.delete(), false);
+assertEq(s.has(), false);
+assertEq(s.add(), undefined);
+assertEq(s.has(), true);
+assertEq(s.delete(), true);
+assertEq(s.has(), false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/for-in.js
@@ -0,0 +1,25 @@
+// for-in loops on Maps and Sets enumerate properties.
+
+var test = function test(obj) {
+    assertEq(Object.keys(obj).length, 0);
+
+    var i = 0, v;
+    for (v in obj)
+        i++;
+    assertEq(i, 0);
+
+    obj.ownProp = 1;
+    assertEq(Object.keys(obj).join(), "ownProp");
+
+    for (v in obj)
+        i++;
+    assertEq(i, 1);
+    assertEq(v, "ownProp");
+
+    delete obj.ownProp;
+};
+
+test(Map.prototype);
+test(new Map);
+test(Set.prototype);
+test(new Set);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/key-equality-0.js
@@ -0,0 +1,37 @@
+// -0 is a distinct key from +0.
+
+var s = new Set;
+s.add(-0);
+assertEq(s.has(0), false);
+assertEq(s.has(-0), true);
+
+assertEq(s.delete(0), false);
+assertEq(s.has(-0), true);
+
+s.add(0);
+assertEq(s.delete(-0), true);
+assertEq(s.has(0), true);
+assertEq(s.has(-0), false);
+
+var m = new Map;
+m.set(-0, 'x');
+assertEq(m.has(0), false);
+assertEq(m.get(0), undefined);
+assertEq(m.has(-0), true);
+assertEq(m.get(-0), 'x');
+
+assertEq(m.delete(0), false);
+assertEq(m.has(-0), true);
+assertEq(m.get(-0), 'x');
+
+m.set(0, 'y');
+assertEq(m.has(0), true);
+assertEq(m.get(0), 'y');
+assertEq(m.has(-0), true);
+assertEq(m.get(-0), 'x');
+
+assertEq(m.delete(-0), true);
+assertEq(m.has(0), true);
+assertEq(m.get(0), 'y');
+assertEq(m.has(-0), false);
+assertEq(m.get(-0), undefined);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/key-equality-1.js
@@ -0,0 +1,28 @@
+// Different representations of the same number or string are treated as the same Map key.
+
+var m = new Map;
+var test = function test(a, b) {
+    m.set(a, 'secret');
+    assertEq(m.get(b), 'secret');
+    m.set(b, 'password');
+    assertEq(m.get(a), 'password');
+
+    assertEq(a, b);
+};
+
+// Float and integer representations of the same number are the same key.
+test(9, Math.sqrt(81));
+
+// Ordinary strings and ropes are the same key.
+var a = Array(1001).join('x');
+var b = Array(501).join('x') + Array(501).join('x');
+test(a, b);
+
+// Two structurally different ropes with the same characters are the same key.
+a = "";
+b = "";
+for (var i = 0; i < 10; i++) {
+    a = Array(501).join('x') + a;
+    b = b + Array(501).join('x');
+}
+test(a, b);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/key-equality-2.js
@@ -0,0 +1,11 @@
+// Number keys are distinct from string keys that would name the same property.
+
+var s = new Set;
+
+s.add(17);
+assertEq(s.has("17"), false);
+assertEq(s.has(17), true);
+s.add("17");
+assertEq(s.delete(17), true);
+assertEq(s.has("17"), true);
+assertEq(s.has(17), false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/key-equality-NaN.js
@@ -0,0 +1,15 @@
+// NaN is equal to itself for the purpose of key lookups.
+
+var m = new Map;
+m.set(NaN, "ok");
+assertEq(m.has(NaN), true);
+assertEq(m.get(NaN), "ok");
+assertEq(m.delete(NaN), true);
+assertEq(m.has(NaN), false);
+assertEq(m.get(NaN), undefined);
+
+var s = new Set;
+s.add(NaN);
+assertEq(s.has(NaN), true);
+assertEq(s.delete(NaN), true);
+assertEq(s.has(NaN), false);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -78,16 +78,17 @@
 #include "jsscript.h"
 #include "jsstr.h"
 #include "prmjtime.h"
 #include "jsweakmap.h"
 #include "jswrapper.h"
 #include "jstypedarray.h"
 
 #include "ds/LifoAlloc.h"
+#include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Util.h" // DebugOnly
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
@@ -1784,16 +1785,18 @@ static JSStdName standard_class_atoms[] 
     {js_InitQNameClass,                 EAGER_ATOM_AND_CLASP(QName)},
 #endif
 #if JS_HAS_GENERATORS
     {js_InitIteratorClasses,            EAGER_ATOM_AND_CLASP(StopIteration)},
 #endif
     {js_InitJSONClass,                  EAGER_ATOM_AND_CLASP(JSON)},
     {js_InitTypedArrayClasses,          EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::slowClass},
     {js_InitWeakMapClass,               EAGER_CLASS_ATOM(WeakMap), &js::WeakMapClass},
+    {js_InitMapClass,                   EAGER_CLASS_ATOM(Map), &js::MapObject::class_},
+    {js_InitSetClass,                   EAGER_CLASS_ATOM(Set), &js::SetObject::class_},
     {NULL,                              0, NULL, NULL}
 };
 
 /*
  * Table of top-level function and constant names and their init functions.
  * If you add a "standard" global function or property, remember to update
  * this table.
  */
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -562,16 +562,21 @@ class Value
 
     JS_ALWAYS_INLINE
     uint32_t payloadAsRawUint32() const {
         JS_ASSERT(!isDouble());
         return data.s.payload.u32;
     }
 
     JS_ALWAYS_INLINE
+    uint64_t asRawBits() const {
+        return data.asBits;
+    }
+
+    JS_ALWAYS_INLINE
     JSValueType extractNonDoubleType() const {
         return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data);
     }
 
     /*
      * Private API
      *
      * Private setters/getters allow the caller to read/write arbitrary types
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -54,17 +54,17 @@
  *  - The array's initialized length, accessible with
  *    getDenseArrayInitializedLength().
  *
  * In dense mode, holes in the array are represented by
  * MagicValue(JS_ARRAY_HOLE) invalid values.
  *
  * NB: the capacity and length of a dense array are entirely unrelated!  The
  * length may be greater than, less than, or equal to the capacity. The first
- * case may occur when the user writes "new Array(100), in which case the
+ * case may occur when the user writes "new Array(100)", in which case the
  * length is 100 while the capacity remains 0 (indices below length and above
  * capacity must be treated as holes). See array_length_setter for another
  * explanation of how the first case may occur.
  *
  * The initialized length of a dense array specifies the number of elements
  * that have been initialized. All elements above the initialized length are
  * holes in the array, and the memory for all elements between the initialized
  * length and capacity is left uninitialized. When type inference is disabled,
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1089,16 +1089,21 @@ class TypeScript
     /*
      * Monitor a bytecode pushing a value which is not accounted for by the
      * inference type constraints, such as integer overflow.
      */
     static inline void MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc);
     static inline void MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc);
     static inline void MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc);
 
+    static inline void GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc);
+    static inline void MonitorOverflow(JSContext *cx);
+    static inline void MonitorString(JSContext *cx);
+    static inline void MonitorUnknown(JSContext *cx);
+
     /*
      * Monitor a bytecode pushing any value. This must be called for any opcode
      * which is JOF_TYPESET, and where either the script has not been analyzed
      * by type inference or where the pc has type barriers. For simplicity, we
      * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
      * and only look at barriers when generating JIT code for the script.
      */
     static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -591,16 +591,50 @@ TypeScript::MonitorString(JSContext *cx,
 /* static */ inline void
 TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
         TypeDynamicResult(cx, script, pc, Type::UnknownType());
 }
 
 /* static */ inline void
+TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
+{
+    *script = cx->fp()->script();
+    *pc = cx->regs().pc;
+}
+
+/* static */ inline void
+TypeScript::MonitorOverflow(JSContext *cx)
+{
+    JSScript *script;
+    jsbytecode *pc;
+    GetPcScript(cx, &script, &pc);
+    MonitorOverflow(cx, script, pc);
+}
+
+/* static */ inline void
+TypeScript::MonitorString(JSContext *cx)
+{
+    JSScript *script;
+    jsbytecode *pc;
+    GetPcScript(cx, &script, &pc);
+    MonitorString(cx, script, pc);
+}
+
+/* static */ inline void
+TypeScript::MonitorUnknown(JSContext *cx)
+{
+    JSScript *script;
+    jsbytecode *pc;
+    GetPcScript(cx, &script, &pc);
+    MonitorUnknown(cx, script, pc);
+}
+
+/* static */ inline void
 TypeScript::MonitorAssign(JSContext *cx, JSScript *script, jsbytecode *pc,
                           JSObject *obj, jsid id, const js::Value &rval)
 {
     if (cx->typeInferenceEnabled() && !obj->hasSingletonType()) {
         /*
          * Mark as unknown any object which has had dynamic assignments to
          * non-integer properties at SETELEM opcodes. This avoids making large
          * numbers of type properties for hashmap-style objects. We don't need
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2408,155 +2408,61 @@ BEGIN_CASE(JSOP_URSH)
     regs.sp--;
     if (!regs.sp[-1].setNumber(uint32_t(u)))
         TypeScript::MonitorOverflow(cx, script, regs.pc);
 }
 END_CASE(JSOP_URSH)
 
 BEGIN_CASE(JSOP_ADD)
 {
+    Value lval = regs.sp[-2];
     Value rval = regs.sp[-1];
-    Value lval = regs.sp[-2];
-
-    if (lval.isInt32() && rval.isInt32()) {
-        int32_t l = lval.toInt32(), r = rval.toInt32();
-        int32_t sum = l + r;
-        if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
-            regs.sp[-2].setDouble(double(l) + double(r));
-            TypeScript::MonitorOverflow(cx, script, regs.pc);
-        } else {
-            regs.sp[-2].setInt32(sum);
-        }
-        regs.sp--;
-    } else
-#if JS_HAS_XML_SUPPORT
-    if (IsXML(lval) && IsXML(rval)) {
-        if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
-            goto error;
-        regs.sp[-2] = rval;
-        regs.sp--;
-        TypeScript::MonitorUnknown(cx, script, regs.pc);
-    } else
-#endif
-    {
-        /*
-         * If either operand is an object, any non-integer result must be
-         * reported to inference.
-         */
-        bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
-
-        if (!ToPrimitive(cx, &lval))
-            goto error;
-        if (!ToPrimitive(cx, &rval))
-            goto error;
-        bool lIsString, rIsString;
-        if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
-            JSString *lstr, *rstr;
-            if (lIsString) {
-                lstr = lval.toString();
-            } else {
-                lstr = ToString(cx, lval);
-                if (!lstr)
-                    goto error;
-                regs.sp[-2].setString(lstr);
-            }
-            if (rIsString) {
-                rstr = rval.toString();
-            } else {
-                rstr = ToString(cx, rval);
-                if (!rstr)
-                    goto error;
-                regs.sp[-1].setString(rstr);
-            }
-            JSString *str = js_ConcatStrings(cx, lstr, rstr);
-            if (!str)
-                goto error;
-            if (lIsObject || rIsObject)
-                TypeScript::MonitorString(cx, script, regs.pc);
-            regs.sp[-2].setString(str);
-            regs.sp--;
-        } else {
-            double l, r;
-            if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
-                goto error;
-            l += r;
-            if (!regs.sp[-2].setNumber(l) &&
-                (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
-                TypeScript::MonitorOverflow(cx, script, regs.pc);
-            }
-            regs.sp--;
-        }
-    }
+    if (!AddOperation(cx, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
 }
 END_CASE(JSOP_ADD)
 
-#define BINARY_OP(OP)                                                         \
-    JS_BEGIN_MACRO                                                            \
-        Value rval = regs.sp[-1];                                             \
-        Value lval = regs.sp[-2];                                             \
-        double d1, d2;                                                        \
-        if (!ToNumber(cx, lval, &d1) || !ToNumber(cx, rval, &d2))             \
-            goto error;                                                       \
-        double d = d1 OP d2;                                                  \
-        regs.sp--;                                                            \
-        if (!regs.sp[-1].setNumber(d) &&                                      \
-            !(lval.isDouble() || rval.isDouble())) {                          \
-            TypeScript::MonitorOverflow(cx, script, regs.pc);                 \
-        }                                                                     \
-    JS_END_MACRO
-
 BEGIN_CASE(JSOP_SUB)
-    BINARY_OP(-);
+{
+    Value lval = regs.sp[-2];
+    Value rval = regs.sp[-1];
+    if (!SubOperation(cx, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
 END_CASE(JSOP_SUB)
 
 BEGIN_CASE(JSOP_MUL)
-    BINARY_OP(*);
+{
+    Value lval = regs.sp[-2];
+    Value rval = regs.sp[-1];
+    if (!MulOperation(cx, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
 END_CASE(JSOP_MUL)
 
-#undef BINARY_OP
-
 BEGIN_CASE(JSOP_DIV)
 {
+    Value lval = regs.sp[-2];
     Value rval = regs.sp[-1];
-    Value lval = regs.sp[-2];
-    double d1, d2;
-    if (!ToNumber(cx, lval, &d1) || !ToNumber(cx, rval, &d2))
+    if (!DivOperation(cx, lval, rval, &regs.sp[-2]))
         goto error;
     regs.sp--;
-
-    regs.sp[-1].setNumber(NumberDiv(d1, d2));
-
-    if (d2 == 0 || (regs.sp[-1].isDouble() && !(lval.isDouble() || rval.isDouble())))
-        TypeScript::MonitorOverflow(cx, script, regs.pc);
 }
 END_CASE(JSOP_DIV)
 
 BEGIN_CASE(JSOP_MOD)
 {
-    Value &lref = regs.sp[-2];
-    Value &rref = regs.sp[-1];
-    int32_t l, r;
-    if (lref.isInt32() && rref.isInt32() &&
-        (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) {
-        int32_t mod = l % r;
-        regs.sp--;
-        regs.sp[-1].setInt32(mod);
-    } else {
-        double d1, d2;
-        if (!ToNumber(cx, regs.sp[-2], &d1) || !ToNumber(cx, regs.sp[-1], &d2))
-            goto error;
-        regs.sp--;
-        if (d2 == 0) {
-            regs.sp[-1].setDouble(js_NaN);
-        } else {
-            d1 = js_fmod(d1, d2);
-            regs.sp[-1].setDouble(d1);
-        }
-        TypeScript::MonitorOverflow(cx, script, regs.pc);
-    }
+    Value lval = regs.sp[-2];
+    Value rval = regs.sp[-1];
+    if (!ModOperation(cx, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
 }
 END_CASE(JSOP_MOD)
 
 BEGIN_CASE(JSOP_NOT)
 {
     Value *_;
     bool cond;
     POP_BOOLEAN(cx, _, cond);
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -39,23 +39,26 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsinterpinlines_h__
 #define jsinterpinlines_h__
 
 #include "jsapi.h"
 #include "jsbool.h"
 #include "jscompartment.h"
+#include "jsinfer.h"
 #include "jsinterp.h"
+#include "jslibmath.h"
 #include "jsnum.h"
 #include "jsprobes.h"
 #include "jsstr.h"
 #include "methodjit/MethodJIT.h"
 
 #include "jsfuninlines.h"
+#include "jsinferinlines.h"
 #include "jspropertycacheinlines.h"
 #include "jstypedarrayinlines.h"
 
 #include "vm/Stack-inl.h"
 
 namespace js {
 
 class AutoPreserveEnumerators {
@@ -506,11 +509,142 @@ ScriptEpilogueOrGeneratorYield(JSContext
 
 inline void
 InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
 {
     if (script == regs->fp()->script())
         enabler.enableInterrupts();
 }
 
+static JS_ALWAYS_INLINE bool
+AddOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+    Value lval = lhs;
+    Value rval = rhs;
+
+    if (lval.isInt32() && rval.isInt32()) {
+        int32_t l = lval.toInt32(), r = rval.toInt32();
+        int32_t sum = l + r;
+        if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
+            res->setDouble(double(l) + double(r));
+            types::TypeScript::MonitorOverflow(cx);
+        } else {
+            res->setInt32(sum);
+        }
+    } else
+#if JS_HAS_XML_SUPPORT
+    if (IsXML(lval) && IsXML(rval)) {
+        if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), res))
+            return false;
+        types::TypeScript::MonitorUnknown(cx);
+    } else
+#endif
+    {
+        /*
+         * If either operand is an object, any non-integer result must be
+         * reported to inference.
+         */
+        bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
+
+        if (!ToPrimitive(cx, &lval))
+            return false;
+        if (!ToPrimitive(cx, &rval))
+            return false;
+        bool lIsString, rIsString;
+        if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
+            js::AutoStringRooter lstr(cx), rstr(cx);
+            if (lIsString) {
+                lstr.setString(lval.toString());
+            } else {
+                lstr.setString(ToString(cx, lval));
+                if (!lstr.string())
+                    return false;
+            }
+            if (rIsString) {
+                rstr.setString(rval.toString());
+            } else {
+                rstr.setString(ToString(cx, rval));
+                if (!rstr.string())
+                    return false;
+            }
+            JSString *str = js_ConcatStrings(cx, lstr.string(), rstr.string());
+            if (!str)
+                return false;
+            if (lIsObject || rIsObject)
+                types::TypeScript::MonitorString(cx);
+            res->setString(str);
+        } else {
+            double l, r;
+            if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
+                return false;
+            l += r;
+            if (!res->setNumber(l) &&
+                (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
+                types::TypeScript::MonitorOverflow(cx);
+            }
+        }
+    }
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+SubOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+    double d = d1 - d2;
+    if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
+        types::TypeScript::MonitorOverflow(cx);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+MulOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+    double d = d1 * d2;
+    if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
+        types::TypeScript::MonitorOverflow(cx);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+DivOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+    res->setNumber(NumberDiv(d1, d2));
+
+    if (d2 == 0 || (res->isDouble() && !(lhs.isDouble() || rhs.isDouble())))
+        types::TypeScript::MonitorOverflow(cx);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+ModOperation(JSContext *cx, const Value &lhs, const Value &rhs, Value *res)
+{
+    int32_t l, r;
+    if (lhs.isInt32() && rhs.isInt32() &&
+        (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
+        int32_t mod = l % r;
+        res->setInt32(mod);
+        return true;
+    }
+
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+
+    if (d2 == 0)
+        res->setDouble(js_NaN);
+    else
+        res->setDouble(js_fmod(d1, d2));
+    types::TypeScript::MonitorOverflow(cx);
+    return true;
+}
+
 }  /* namespace js */
 
 #endif /* jsinterpinlines_h__ */
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -74,16 +74,17 @@
 #include "jsscript.h"
 #include "jsstdint.h"
 #include "jsstr.h"
 #include "jsdbgapi.h"
 #include "json.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
+#include "builtin/MapObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "js/MemoryMetrics.h"
 
 #include "jsarrayinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
@@ -6545,17 +6546,19 @@ js_GetterOnlyPropertyStub(JSContext *cx,
 
 void
 js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
 {
     Value &thisv = call.thisv();
 
 #ifdef DEBUG
     if (thisv.isObject()) {
-        JS_ASSERT(thisv.toObject().getClass() != clasp);
+        JS_ASSERT(thisv.toObject().getClass() != clasp ||
+                  !thisv.toObject().getProto() ||
+                  thisv.toObject().getProto()->getClass() != clasp);
     } else if (thisv.isString()) {
         JS_ASSERT(clasp != &StringClass);
     } else if (thisv.isNumber()) {
         JS_ASSERT(clasp != &NumberClass);
     } else if (thisv.isBoolean()) {
         JS_ASSERT(clasp != &BooleanClass);
     } else {
         JS_ASSERT(thisv.isUndefined() || thisv.isNull());
--- a/js/src/jsproto.tbl
+++ b/js/src/jsproto.tbl
@@ -87,12 +87,14 @@ JS_PROTO(Uint16Array,           28,     
 JS_PROTO(Int32Array,            29,     js_InitTypedArrayClasses)
 JS_PROTO(Uint32Array,           30,     js_InitTypedArrayClasses)
 JS_PROTO(Float32Array,          31,     js_InitTypedArrayClasses)
 JS_PROTO(Float64Array,          32,     js_InitTypedArrayClasses)
 JS_PROTO(Uint8ClampedArray,     33,     js_InitTypedArrayClasses)
 JS_PROTO(Proxy,                 34,     js_InitProxyClass)
 JS_PROTO(AnyName,               35,     js_InitNullClass)
 JS_PROTO(WeakMap,               36,     js_InitWeakMapClass)
+JS_PROTO(Map,                   37,     js_InitMapClass)
+JS_PROTO(Set,                   38,     js_InitSetClass)
 
 #undef XML_INIT
 #undef NAMESPACE_INIT
 #undef QNAME_INIT
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -365,17 +365,17 @@ PodEqual(T *one, T *two, size_t len)
 
 JS_ALWAYS_INLINE static size_t
 UnsignedPtrDiff(const void *bigger, const void *smaller)
 {
     return size_t(bigger) - size_t(smaller);
 }
 
 /*
- * Ordinarily, a function taking a JSContext* 'cx' paremter reports errors on
+ * Ordinarily, a function taking a JSContext* 'cx' parameter reports errors on
  * the context. In some cases, functions optionally report and indicate this by
  * taking a nullable 'maybecx' parameter. In some cases, though, a function
  * always needs a 'cx', but optionally reports. This option is presented by the
  * MaybeReportError.
  */
 enum MaybeReportError { REPORT_ERROR = true, DONT_REPORT_ERROR = false };
 
 }  /* namespace js */
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -1121,17 +1121,17 @@ class GetPropCompiler : public PICStubCo
         repatcher.patchAddressOffsetForValueLoad(labels.getValueLoad(pic.fastPathRejoin), offset);
 
         pic.inlinePathPatched = true;
 
         return Lookup_Cacheable;
     }
 
     void generateGetterStub(Assembler &masm, const Shape *shape,
-                            Label start, const Vector<Jump, 8> &shapeMismatches)
+                            Label start, Vector<Jump, 8> &shapeMismatches)
     {
         /*
          * Getter hook needs to be called from the stub. The state is fully
          * synced and no registers are live except the result registers.
          */
         JS_ASSERT(pic.canCallHook);
         PropertyOp getter = shape->getterOp();
 
@@ -1299,17 +1299,17 @@ class GetPropCompiler : public PICStubCo
 
         linkerEpilogue(buffer, start, shapeMismatches);
 
         if (setStubShapeOffset)
             pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
         return Lookup_Cacheable;
     }
 
-    void linkerEpilogue(LinkerHelper &buffer, Label start, const Vector<Jump, 8> &shapeMismatches)
+    void linkerEpilogue(LinkerHelper &buffer, Label start, Vector<Jump, 8> &shapeMismatches)
     {
         // The guard exit jumps to the original slow case.
         for (Jump *pj = shapeMismatches.begin(); pj != shapeMismatches.end(); ++pj)
             buffer.link(*pj, pic.slowPathStart);
 
         CodeLocationLabel cs = buffer.finalize(f);
         JaegerSpew(JSpew_PICs, "generated %s stub at %p\n", type, cs.executableAddress());
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1161,17 +1161,17 @@ Debugger::markAllIteratively(GCMarker *t
             GlobalObject *global = r.front();
 
             /*
              * Every debuggee has at least one debugger, so in this case
              * getDebuggers can't return NULL.
              */
             const GlobalObject::DebuggerVector *debuggers = global->getDebuggers();
             JS_ASSERT(debuggers);
-            for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
+            for (Debugger * const *p = debuggers->begin(); p != debuggers->end(); p++) {
                 Debugger *dbg = *p;
 
                 /*
                  * dbg is a Debugger with at least one debuggee. Check three things:
                  *   - dbg is actually in a compartment being GC'd
                  *   - it isn't already marked
                  *   - it actually has hooks that might be called
                  */
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -41,16 +41,17 @@
 #include "GlobalObject.h"
 
 #include "jscntxt.h"
 #include "jsexn.h"
 #include "jsmath.h"
 #include "json.h"
 #include "jsweakmap.h"
 
+#include "builtin/MapObject.h"
 #include "builti