Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Wed, 21 Mar 2012 15:35:48 -0700
changeset 106050 2af0fc82c983cee51ae73807750ccb79e699dda5
parent 106049 c223b4370b3ada9227632136a9b51511cb5d0524 (current diff)
parent 90019 9023803c5d649c5b62fab56e672c3a0286a0517d (diff)
child 106051 61129d29a37770602c7e8afe650b3eab10f401e7
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
browser/base/content/browser.js
browser/base/content/browser.xul
browser/components/migration/src/nsIEProfileMigrator.cpp
browser/components/migration/src/nsSafariProfileMigrator.cpp
content/base/public/mozISanitizingSerializer.h
content/base/public/nsContentUtils.h
content/base/src/Makefile.in
content/base/src/mozSanitizingSerializer.cpp
content/base/src/mozSanitizingSerializer.h
content/base/src/nsContentUtils.cpp
content/base/src/nsTreeSanitizer.cpp
content/base/src/nsXMLHttpRequest.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/events/src/nsDOMDataTransfer.cpp
content/events/src/nsDOMDataTransfer.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/content/test/file_fullscreen-api.html
content/html/document/src/nsHTMLContentSink.cpp
content/smil/nsSMILAnimationController.cpp
content/smil/nsSMILAnimationController.h
content/svg/content/src/nsSVGDataParser.cpp
content/svg/content/src/nsSVGFilters.cpp
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/src/nsSVGSwitchElement.cpp
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/system/nsDeviceMotion.cpp
dom/system/nsDeviceMotion.h
dom/system/windows/nsDeviceMotionSystem.cpp
dom/system/windows/nsDeviceMotionSystem.h
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/text/nsPlaintextDataTransfer.cpp
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
embedding/android/Makefile.in
gfx/gl/GLContext.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLContextProviderOSMesa.cpp
gfx/gl/GLContextProviderWGL.cpp
gfx/thebes/gfxFont.cpp
image/src/DiscardTracker.cpp
image/src/imgRequest.cpp
image/test/mochitest/Makefile.in
js/src/gc/Barrier.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/jsprobes.cpp
js/src/jsutil.h
js/src/jsval.h
js/src/methodjit/PolyIC.cpp
js/src/vm/ArgumentsObject.cpp
layout/base/crashtests/crashtests.list
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsPresShell.cpp
layout/build/nsLayoutModule.cpp
layout/generic/crashtests/crashtests.list
layout/generic/nsFrame.cpp
layout/reftests/bugs/reftest.list
layout/reftests/svg/reftest.list
layout/svg/base/src/nsISVGChildFrame.h
layout/svg/base/src/nsISVGGlyphFragmentNode.h
layout/svg/base/src/nsSVGClipPathFrame.cpp
layout/svg/base/src/nsSVGClipPathFrame.h
layout/svg/base/src/nsSVGContainerFrame.cpp
layout/svg/base/src/nsSVGContainerFrame.h
layout/svg/base/src/nsSVGEffects.cpp
layout/svg/base/src/nsSVGEffects.h
layout/svg/base/src/nsSVGFilterFrame.cpp
layout/svg/base/src/nsSVGForeignObjectFrame.cpp
layout/svg/base/src/nsSVGForeignObjectFrame.h
layout/svg/base/src/nsSVGGeometryFrame.cpp
layout/svg/base/src/nsSVGGeometryFrame.h
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/svg/base/src/nsSVGGlyphFrame.h
layout/svg/base/src/nsSVGGradientFrame.h
layout/svg/base/src/nsSVGImageFrame.cpp
layout/svg/base/src/nsSVGInnerSVGFrame.cpp
layout/svg/base/src/nsSVGInnerSVGFrame.h
layout/svg/base/src/nsSVGIntegrationUtils.cpp
layout/svg/base/src/nsSVGIntegrationUtils.h
layout/svg/base/src/nsSVGMarkerFrame.cpp
layout/svg/base/src/nsSVGMarkerFrame.h
layout/svg/base/src/nsSVGMaskFrame.cpp
layout/svg/base/src/nsSVGMaskFrame.h
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.h
layout/svg/base/src/nsSVGPaintServerFrame.h
layout/svg/base/src/nsSVGPathGeometryFrame.cpp
layout/svg/base/src/nsSVGPathGeometryFrame.h
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.h
layout/svg/base/src/nsSVGSwitchFrame.cpp
layout/svg/base/src/nsSVGTSpanFrame.h
layout/svg/base/src/nsSVGTextFrame.cpp
layout/svg/base/src/nsSVGTextFrame.h
layout/svg/base/src/nsSVGUseFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
layout/svg/base/src/nsSVGUtils.h
memory/jemalloc/jemalloc.c
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/themes/core/gingerbread/browser.css
mobile/android/themes/core/gingerbread/content.css
mobile/android/themes/core/gingerbread/defines.inc
mobile/android/themes/core/gingerbread/images/alert-addons-30.png
mobile/android/themes/core/gingerbread/images/alert-downloads-30.png
mobile/android/themes/core/gingerbread/images/arrowdown-16.png
mobile/android/themes/core/gingerbread/images/arrowleft-16.png
mobile/android/themes/core/gingerbread/images/arrowright-16.png
mobile/android/themes/core/gingerbread/images/errorpage-larry-black.png
mobile/android/themes/core/gingerbread/images/errorpage-larry-white.png
mobile/android/themes/core/gingerbread/images/errorpage-warning.png
mobile/android/themes/core/gingerbread/images/forward-default-hdpi.png
mobile/android/themes/core/gingerbread/images/mute-hdpi.png
mobile/android/themes/core/gingerbread/images/pause-hdpi.png
mobile/android/themes/core/gingerbread/images/play-hdpi.png
mobile/android/themes/core/gingerbread/images/popup-selected-item-hdpi.png
mobile/android/themes/core/gingerbread/images/remotetabs-32.png
mobile/android/themes/core/gingerbread/images/scrubber-hdpi.png
mobile/android/themes/core/gingerbread/images/search-clear-30.png
mobile/android/themes/core/gingerbread/images/throbber.png
mobile/android/themes/core/gingerbread/images/unmute-hdpi.png
mobile/android/themes/core/gingerbread/images/urlbar-bg.png
mobile/android/themes/core/honeycomb/browser.css
mobile/android/themes/core/honeycomb/defines.inc
mobile/android/themes/core/honeycomb/images/alert-addons-30.png
mobile/android/themes/core/honeycomb/images/alert-downloads-30.png
mobile/android/themes/core/honeycomb/images/arrowdown-16.png
mobile/android/themes/core/honeycomb/images/arrowleft-16.png
mobile/android/themes/core/honeycomb/images/arrowright-16.png
mobile/android/themes/core/honeycomb/images/errorpage-larry-black.png
mobile/android/themes/core/honeycomb/images/errorpage-larry-white.png
mobile/android/themes/core/honeycomb/images/errorpage-warning.png
mobile/android/themes/core/honeycomb/images/forward-default-hdpi.png
mobile/android/themes/core/honeycomb/images/mute-hdpi.png
mobile/android/themes/core/honeycomb/images/pause-hdpi.png
mobile/android/themes/core/honeycomb/images/play-hdpi.png
mobile/android/themes/core/honeycomb/images/popup-selected-item-hdpi.png
mobile/android/themes/core/honeycomb/images/remotetabs-32.png
mobile/android/themes/core/honeycomb/images/scrubber-hdpi.png
mobile/android/themes/core/honeycomb/images/search-clear-30.png
mobile/android/themes/core/honeycomb/images/sidebarbutton-active-hdpi.png
mobile/android/themes/core/honeycomb/images/throbber.png
mobile/android/themes/core/honeycomb/images/unmute-hdpi.png
mobile/android/themes/core/images/alert-addons-30.png
mobile/android/themes/core/images/alert-downloads-30.png
mobile/android/themes/core/images/forward-default-hdpi.png
mobile/android/themes/core/images/popup-selected-item-hdpi.png
mobile/android/themes/core/images/remotetabs-32.png
mobile/android/themes/core/images/sidebarbutton-active-hdpi.png
modules/libpref/src/init/all.js
netwerk/mime/nsMIMEHeaderParamImpl.cpp
netwerk/protocol/http/SpdySession.cpp
netwerk/protocol/http/SpdySession.h
netwerk/protocol/http/nsAHttpConnection.h
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttp.cpp
netwerk/protocol/http/nsHttp.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnection.h
netwerk/protocol/http/nsHttpConnectionInfo.cpp
netwerk/protocol/http/nsHttpConnectionInfo.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpHandler.h
netwerk/protocol/http/nsHttpPipeline.cpp
netwerk/protocol/http/nsHttpPipeline.h
netwerk/protocol/http/nsHttpTransaction.cpp
netwerk/protocol/http/nsHttpTransaction.h
parser/html/nsHtml5Parser.cpp
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOpExecutor.h
parser/html/nsHtml5TreeOperation.cpp
parser/html/nsParserUtils.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/content/license.html
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/nsAppShell.cpp
widget/android/nsLookAndFeel.cpp
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/nsIWidget.h
widget/xpwidgets/nsBaseWidget.h
xpcom/string/public/nsTSubstring.h
xpcom/string/src/nsTSubstring.cpp
xpfe/appshell/src/nsXULWindow.cpp
--- a/accessible/tests/mochitest/test_nsIAccessibleDocument.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleDocument.html
@@ -10,18 +10,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <script type="application/javascript"
     src="common.js"></script>
   <script type="application/javascript"
     src="role.js"></script>
   <script type="application/javascript"
     src="states.js"></script>
 
+  <!-- chrome-harness.js breaks this test (bug 736886) -->
+  <!--
   <script type="application/javascript"
           src="chrome://mochikit/content/chrome-harness.js"/>
+  -->
 
   <script type="application/javascript">
     function doTest()
     {
       var docAcc = getAccessible(document, [nsIAccessibleDocument]);
       if (docAcc) {
         // nsIAccessible
         is(docAcc.name, "nsIAccessibleDocument chrome tests",
@@ -36,19 +39,24 @@ https://bugzilla.mozilla.org/show_bug.cg
         is(docAcc.numActions, 0, "Wrong number of actions for document!");
 
         // attributes should contain tag:body
         attributes = docAcc.attributes;
         is(attributes.getStringProperty("tag"), "BODY",
            "Wrong attribute on document!");
 
         // nsIAccessibleDocument
+        // getRootDirectory() depends on broken chrome-harness.js include (bug
+        // 736886)
+        /*
         var rootDir = getRootDirectory(window.location.href);
         is(docAcc.URL, rootDir.path + "test_nsIAccessibleDocument.html",
            "Wrong URL for document!");
+        */
+        todo(false, "chrome-harness.js include is broken (bug 736886)");
         is(docAcc.title, "nsIAccessibleDocument chrome tests",        
            "Wrong title for document!");
         is(docAcc.mimeType, "text/html",
            "Wrong mime type for document!");
         // nsDocAccessible::getDocType currently returns NS_ERROR_FAILURE.
         // See bug 442005. After fixing, please remove this comment and
         // uncomment the below two lines to enable the test.
 //        is(docAcc.docType, "HTML",
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -435,16 +435,17 @@ pref("b2g.remote-js.enabled", true);
 pref("b2g.remote-js.port", 9999);
 
 // Handle hardware buttons in the b2g chrome package
 pref("b2g.keys.menu.enabled", true);
 pref("b2g.keys.search.enabled", false);
 
 // Screen timeout in minutes
 pref("power.screen.timeout", 60);
+pref("dom.power.whitelist", "http://localhost:7777");
 
 pref("full-screen-api.enabled", true);
 
 pref("media.volume.steps", 10);
 
 // Data connection settings. These will eventually live in the
 // navigator.settings API, or even in a database where we can look
 // it up automatically (bug 729440), but for this will have to do.
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -437,16 +437,20 @@ CustomEventManager = {
     let detail = evt.detail;
     dump("XXX FIXME : Got a mozContentEvent: " + detail.type);
 
     switch(detail.type) {
       case "desktop-notification-click":
       case "desktop-notification-close":
         AlertsHelper.handleEvent(detail);
         break;
+      case "webapps-install-granted":
+      case "webapps-install-denied":
+        WebappsHelper.handleEvent(detail);
+        break;
     }
   }
 }
 
 AlertsHelper = {
   _listeners: {},
   _count: 0,
 
@@ -473,23 +477,56 @@ AlertsHelper = {
                                                               cookie, alertListener, name) {
     let id = this.registerListener(cookie, alertListener);
     shell.sendEvent(content, "mozChromeEvent", { type: "desktop-notification", id: id, icon: imageUrl, 
                                                  title: title, text: text } );
   }
 }
 
 WebappsHelper = {
+  _installers: {},
+  _count: 0,
+
   init: function webapps_init() {
     Services.obs.addObserver(this, "webapps-launch", false);
+    Services.obs.addObserver(this, "webapps-ask-install", false);
+  },
+
+  registerInstaller: function webapps_registerInstaller(data) {
+    let id = "installer" + this._count++;
+    this._installers[id] = data;
+    return id;
+  },
+
+  handleEvent: function webapps_handleEvent(detail) {
+    if (!detail || !detail.id)
+      return;
+
+    let installer = this._installers[detail.id];
+    switch (detail.type) {
+      case "webapps-install-granted":
+        DOMApplicationRegistry.confirmInstall(installer);
+        break;
+      case "webapps-install-denied":
+        DOMApplicationRegistry.denyInstall(installer);
+        break;
+    }
   },
 
   observe: function webapps_observe(subject, topic, data) {
     let json = JSON.parse(data);
-    DOMApplicationRegistry.getManifestFor(json.origin, function(aManifest) {
-      if (!aManifest)
-        return;
+    switch(topic) {
+      case "webapps-launch":
+        DOMApplicationRegistry.getManifestFor(json.origin, function(aManifest) {
+          if (!aManifest)
+            return;
 
-      let manifest = new DOMApplicationManifest(aManifest, json.origin);
-      shell.sendEvent(content, "mozChromeEvent", { type: "webapps-launch", url: manifest.fullLaunchPath(), origin: json.origin });
-    });
+          let manifest = new DOMApplicationManifest(aManifest, json.origin);
+          shell.sendEvent(content, "mozChromeEvent", { type: "webapps-launch", url: manifest.fullLaunchPath(), origin: json.origin });
+        });
+        break;
+      case "webapps-ask-install":
+        let id = this.registerInstaller(json);
+        shell.sendEvent(content, "mozChromeEvent", { type: "webapps-ask-install", id: id, app: json.app } );
+        break;
+    }
   }
 }
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -145,26 +145,24 @@ const DEFAULT_SNIPPETS_URLS = [
   "http://www.mozilla.com/firefox/features/?WT.mc_ID=default1"
 , "https://addons.mozilla.org/firefox/?src=snippet&WT.mc_ID=default2"
 ];
 
 const SNIPPETS_UPDATE_INTERVAL_MS = 86400000; // 1 Day.
 
 let gSearchEngine;
 
-function onLoad(event)
-{
+document.addEventListener("DOMContentLoaded", function init() {
   setupSearchEngine();
   document.getElementById("searchText").focus();
 
   loadSnippets();
-
-  fitToWidth();
-  window.addEventListener("resize", fitToWidth);
-}
+});
+window.addEventListener("load", fitToWidth);
+window.addEventListener("resize", fitToWidth);
 
 
 function onSearchSubmit(aEvent)
 {
   let searchTerms = document.getElementById("searchText").value;
   if (gSearchEngine && searchTerms.length > 0) {
     const SEARCH_TOKENS = {
       "_searchTerms_": encodeURIComponent(searchTerms)
--- a/browser/base/content/abouthome/aboutHome.xhtml
+++ b/browser/base/content/abouthome/aboutHome.xhtml
@@ -62,17 +62,17 @@
           href="chrome://branding/content/icon16.png"/>
     <link rel="stylesheet" type="text/css" media="all"
           href="chrome://browser/content/abouthome/aboutHome.css"/>
 
     <script type="text/javascript;version=1.8"
             src="chrome://browser/content/abouthome/aboutHome.js"/>
   </head>
 
-  <body dir="&locale.dir;" onload="onLoad(event)">
+  <body dir="&locale.dir;">
     <div class="spacer"/>
     <div id="topSection">
       <img id="brandLogo" src="chrome://branding/content/about-logo.png" alt=""/>
 
       <div id="searchContainer">
         <form name="searchForm" id="searchForm" onsubmit="onSearchSubmit(event)">
           <div id="searchLogoContainer"><img id="searchEngineLogo"/></div>
           <input type="text" name="q" value="" id="searchText" maxlength="256"/>
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -286,26 +286,26 @@
                               accesskey="&fullZoomToggleCmd.accesskey;"
                               type="checkbox"
                               command="cmd_fullZoomToggle"
                               checked="false"/>
                   </menupopup>
                 </menu>
                 <menu id="pageStyleMenu" label="&pageStyleMenu.label;"
                       accesskey="&pageStyleMenu.accesskey;" observes="isImage">
-                  <menupopup onpopupshowing="gPageStyleMenu.fillPopup(this);"
-                             oncommand="gPageStyleMenu.switchStyleSheet(event.target.getAttribute('data'));">
+                  <menupopup onpopupshowing="gPageStyleMenu.fillPopup(this);">
                     <menuitem id="menu_pageStyleNoStyle"
                               label="&pageStyleNoStyle.label;"
                               accesskey="&pageStyleNoStyle.accesskey;"
-                              oncommand="gPageStyleMenu.disableStyle(); event.stopPropagation();"
+                              oncommand="gPageStyleMenu.disableStyle();"
                               type="radio"/>
                     <menuitem id="menu_pageStylePersistentOnly"
                               label="&pageStylePersistentOnly.label;"
                               accesskey="&pageStylePersistentOnly.accesskey;"
+                              oncommand="gPageStyleMenu.switchStyleSheet('');"
                               type="radio"
                               checked="true"/>
                     <menuseparator/>
                   </menupopup>
                 </menu>
 #include browser-charsetmenu.inc
                 <menuseparator/>
                 <menuitem id="fullScreenItem"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -151,16 +151,19 @@ XPCOMUtils.defineLazyGetter(window, "gFi
   Cu.import("resource://gre/modules/PluralForm.jsm");
   return this.PluralForm;
 });
 __defineSetter__("PluralForm", function (val) {
   delete this.PluralForm;
   return this.PluralForm = val;
 });
 
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
+                                  "resource:///modules/TelemetryStopwatch.jsm");
+
 #ifdef MOZ_SERVICES_SYNC
 XPCOMUtils.defineLazyGetter(this, "Weave", function() {
   let tmp = {};
   Cu.import("resource://services-sync/main.js", tmp);
   return tmp.Weave;
 });
 #endif
 
@@ -3639,16 +3642,29 @@ function toOpenWindowByType(inType, uri,
   else if (features)
     window.open(uri, "_blank", features);
   else
     window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
 }
 
 function OpenBrowserWindow()
 {
+  var telemetryObj = {};
+  TelemetryStopwatch.start("FX_NEW_WINDOW_MS", telemetryObj);
+
+  function newDocumentShown(doc, topic, data) {
+    if (topic == "document-shown" &&
+        doc != document &&
+        doc.defaultView == win) {
+      Services.obs.removeObserver(newDocumentShown, "document-shown");
+      TelemetryStopwatch.finish("FX_NEW_WINDOW_MS", telemetryObj);
+    }
+  };
+  Services.obs.addObserver(newDocumentShown, "document-shown", false);
+
   var charsetArg = new String();
   var handler = Components.classes["@mozilla.org/browser/clh;1"]
                           .getService(Components.interfaces.nsIBrowserHandler);
   var defaultArgs = handler.defaultArgs;
   var wintype = document.documentElement.getAttribute('windowtype');
 
   // if and only if the current window is a browser window and it has a document with a character
   // set, then extract the current charset menu setting from the current document and use it to
@@ -3895,19 +3911,32 @@ var FullScreen = {
   _XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
   toggle: function (event) {
     var enterFS = window.fullScreen;
 
     // We get the fullscreen event _before_ the window transitions into or out of FS mode.
     if (event && event.type == "fullscreen")
       enterFS = !enterFS;
 
-    // show/hide all menubars, toolbars (except the full screen toolbar)
+    // Toggle the View:FullScreen command, which controls elements like the
+    // fullscreen menuitem, menubars, and the appmenu.
+    document.getElementById("View:FullScreen").setAttribute("checked", enterFS);
+
+    // On OS X Lion we don't want to hide toolbars when entering fullscreen, unless
+    // we're entering DOM fullscreen, in which case we should hide the toolbars.
+    // If we're leaving fullscreen, then we'll go through the exit code below to
+    // make sure toolbars are made visible in the case of DOM fullscreen.
+    if (enterFS && this.useLionFullScreen) {
+      if (document.mozFullScreen)
+        this.showXULChrome("toolbar", false);
+      return;
+    }
+
+    // show/hide menubars, toolbars (except the full screen toolbar)
     this.showXULChrome("toolbar", !enterFS);
-    document.getElementById("View:FullScreen").setAttribute("checked", enterFS);
 
     if (enterFS) {
       // Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
       // This will help simulate the "collapse" metaphor while also requiring less code and
       // events than raw listening of mouse coords. We don't add the toolbar in DOM full-screen
       // mode, only browser full-screen mode.
       if (!document.mozFullScreen) {
         let fullScrToggler = document.getElementById("fullscr-toggler");
@@ -4005,17 +4034,18 @@ var FullScreen = {
     this.showWarning(true);
 
     // Exit DOM full-screen mode upon open, close, or change tab.
     gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen);
     gBrowser.tabContainer.addEventListener("TabClose", this.exitDomFullScreen);
     gBrowser.tabContainer.addEventListener("TabSelect", this.exitDomFullScreen);
 
     // Exit DOM full-screen mode when the browser window loses focus (ALT+TAB, etc).
-    if (gPrefService.getBoolPref("full-screen-api.exit-on-deactivate")) {
+    if (!this.useLionFullScreen &&
+        gPrefService.getBoolPref("full-screen-api.exit-on-deactivate")) {
       window.addEventListener("deactivate", this);
     }
 
     // Cancel any "hide the toolbar" animation which is in progress, and make
     // the toolbar hide immediately.
     this._cancelAnimation();
     this.mouseoverToggle(false);
 
@@ -4041,17 +4071,19 @@ var FullScreen = {
       if (fullScrToggler) {
         fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
         fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
       }
       this.cancelWarning();
       gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
       gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
       gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
-      window.removeEventListener("deactivate", this);
+      if (this.useLionFullScreen) {
+        window.removeEventListener("deactivate", this);
+      }
     }
   },
 
   observe: function(aSubject, aTopic, aData)
   {
     if (aData == "browser.fullscreen.autohide") {
       if (gPrefService.getBoolPref("browser.fullscreen.autohide")) {
         gBrowser.mPanelContainer.addEventListener("mousemove",
@@ -4391,16 +4423,28 @@ var FullScreen = {
       fullscreenflex.setAttribute("fullscreencontrol", "true");
     }
 
     var controls = document.getElementsByAttribute("fullscreencontrol", "true");
     for (var i = 0; i < controls.length; ++i)
       controls[i].hidden = aShow;
   }
 };
+XPCOMUtils.defineLazyGetter(FullScreen, "useLionFullScreen", function() {
+  // We'll only use OS X Lion full screen if we're
+  // * on OS X
+  // * on Lion (Darwin 11.x) -- this will need to be updated for OS X 10.8
+  // * have fullscreenbutton="true"
+#ifdef XP_MACOSX
+  return /^11\./.test(Services.sysinfo.getProperty("version")) &&
+         document.documentElement.getAttribute("fullscreenbutton") == "true";
+#else
+  return false;
+#endif
+});
 
 /**
  * Returns true if |aMimeType| is text-based, false otherwise.
  *
  * @param aMimeType
  *        The MIME type to check.
  *
  * If adding types to this function, please also check the similar
@@ -6151,52 +6195,50 @@ var gPageStyleMenu = {
         lastWithSameTitle = currentStyleSheets[currentStyleSheet.title];
 
       if (!lastWithSameTitle) {
         let menuItem = document.createElement("menuitem");
         menuItem.setAttribute("type", "radio");
         menuItem.setAttribute("label", currentStyleSheet.title);
         menuItem.setAttribute("data", currentStyleSheet.title);
         menuItem.setAttribute("checked", !currentStyleSheet.disabled && !styleDisabled);
+        menuItem.setAttribute("oncommand", "gPageStyleMenu.switchStyleSheet(this.getAttribute('data'));");
         menuPopup.appendChild(menuItem);
         currentStyleSheets[currentStyleSheet.title] = menuItem;
       } else if (currentStyleSheet.disabled) {
         lastWithSameTitle.removeAttribute("checked");
       }
     }
 
     noStyle.setAttribute("checked", styleDisabled);
     persistentOnly.setAttribute("checked", !altStyleSelected && !styleDisabled);
     persistentOnly.hidden = (window.content.document.preferredStyleSheetSet) ? haveAltSheets : false;
     sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets;
-    return true;
   },
 
   _stylesheetInFrame: function (frame, title) {
     return Array.some(frame.document.styleSheets,
                       function (stylesheet) stylesheet.title == title);
   },
 
   _stylesheetSwitchFrame: function (frame, title) {
     var docStyleSheets = frame.document.styleSheets;
 
     for (let i = 0; i < docStyleSheets.length; ++i) {
       let docStyleSheet = docStyleSheets[i];
 
-      if (title == "_nostyle")
-        docStyleSheet.disabled = true;
-      else if (docStyleSheet.title)
+      if (docStyleSheet.title)
         docStyleSheet.disabled = (docStyleSheet.title != title);
       else if (docStyleSheet.disabled)
         docStyleSheet.disabled = false;
     }
   },
 
   _stylesheetSwitchAll: function (frameset, title) {
-    if (!title || title == "_nostyle" || this._stylesheetInFrame(frameset, title))
+    if (!title || this._stylesheetInFrame(frameset, title))
       this._stylesheetSwitchFrame(frameset, title);
 
     for (let i = 0; i < frameset.frames.length; i++)
       this._stylesheetSwitchAll(frameset.frames[i], title);
   },
 
   switchStyleSheet: function (title, contentWindow) {
     getMarkupDocumentViewer().authorStyleDisabled = false;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -89,16 +89,17 @@
 #endif
         titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
         lightweightthemes="true"
         lightweightthemesfooter="browser-bottombox"
         windowtype="navigator:browser"
         macanimationtype="document"
         screenX="4" screenY="4"
         browsingmode="normal"
+        fullscreenbutton="true"
         persist="screenX screenY width height sizemode">
 
 # All JS files which are not content (only) dependent that browser.xul
 # wishes to include *must* go into the global-scripts.inc file
 # so that they can be shared by macBrowserOverlay.xul.
 #include global-scripts.inc
 <script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/>
 
@@ -1054,17 +1055,17 @@
 #ifndef XP_UNIX
   <svg:svg height="0">
     <svg:mask id="winstripe-keyhole-forward-mask" maskContentUnits="objectBoundingBox">
       <svg:rect x="0" y="0" width="1" height="1" fill="white"/>
       <svg:circle cx="-0.34" cy="0.5" r="0.61"/>
     </svg:mask>
     <svg:mask id="winstripe-urlbar-back-button-mask" maskContentUnits="userSpaceOnUse">
       <svg:rect x="0" y="0" width="10000" height="50" fill="white"/>
-      <svg:circle cx="-11" cy="13" r="15"/>
+      <svg:circle cx="-11" cy="18" r="15"/>
     </svg:mask>
   </svg:svg>
 #endif
 #ifdef XP_MACOSX
   <svg:svg height="0">
     <svg:mask id="pinstripe-keyhole-forward-mask" maskContentUnits="objectBoundingBox">
       <svg:rect x="0" y="0" width="1" height="1" fill="white"/>
       <svg:circle cx="-0.41" cy="0.5" r="0.65"/>
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -25,17 +25,16 @@ CPPSRCS = nsModule.cpp \
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS	+= $(call EXPAND_LIBNAME,ole32 shell32)
 endif
 
 LOCAL_INCLUDES = \
 	-I$(srcdir)/../shell/src \
 	-I$(srcdir)/../feeds/src \
-	-I$(srcdir)/../places/src \
 	-I$(srcdir)/../privatebrowsing/src \
 	-I$(srcdir)/../about \
 	-I$(srcdir)/../dirprovider \
 	$(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,version)
 endif
@@ -48,20 +47,24 @@ SHARED_LIBRARY_LIBS = \
 	$(NULL)
 
 ifneq (,$(filter windows cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
 SHARED_LIBRARY_LIBS += ../shell/src/$(LIB_PREFIX)shellservice_s.$(LIB_SUFFIX)
 endif
 
 EXTRA_DSO_LDOPTS += \
 	$(call EXPAND_LIBNAME_PATH,unicharutil_external_s,$(LIBXUL_DIST)/lib) \
-	$(LIBXUL_DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
+	$(XPCOM_GLUE_LDOPTS) \
 	$(MOZ_COMPONENT_LIBS) \
 	$(NULL)
 
+ifdef JS_SHARED_LIBRARY
+EXTRA_DSO_LDOPTS += $(MOZ_JS_LIBS)
+endif
+
 LOCAL_INCLUDES += -I$(srcdir)/../migration/src
 SHARED_LIBRARY_LIBS += ../migration/src/$(LIB_PREFIX)migration_s.$(LIB_SUFFIX)
 
 # Mac: Need to link with CoreFoundation for Mac Migrators (PList reading code)
 # GTK2: Need to link with glib for GNOME shell service
 ifneq (,$(filter cocoa gtk2,$(MOZ_WIDGET_TOOLKIT)))
 EXTRA_DSO_LDOPTS += \
   $(TK_LIBS) \
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -1,49 +1,20 @@
-# ***** 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 The Browser Profile Migrator.
-#
-# The Initial Developer of the Original Code is Ben Goodger.
-# Portions created by the Initial Developer are Copyright (C) 2004
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#   Ben Goodger <ben@bengoodger.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 *****
+/* 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/. */
 
-const kIMig = Components.interfaces.nsIBrowserProfileMigrator;
-const kIPStartup = Components.interfaces.nsIProfileStartup;
-const kProfileMigratorContractIDPrefix = "@mozilla.org/profile/migrator;1?app=browser&type=";
 const Cc = Components.classes;
 const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+const kIMig = Ci.nsIBrowserProfileMigrator;
+const kIPStartup = Ci.nsIProfileStartup;
+
+Cu.import("resource://gre/modules/MigrationUtils.jsm");
 
 var MigrationWizard = {
   _source: "",                  // Source Profile Migrator ContractID suffix
   _itemsFlags: kIMig.ALL,       // Selected Import Data Sources (16-bit bitfield)
   _selectedProfile: null,       // Selected Profile name to import from
   _wiz: null,
   _migrator: null,
   _autoMigrate: null,
@@ -82,16 +53,17 @@ var MigrationWizard = {
   {
     var os = Components.classes["@mozilla.org/observer-service;1"]
                        .getService(Components.interfaces.nsIObserverService);
     os.removeObserver(this, "Migration:Started");
     os.removeObserver(this, "Migration:ItemBeforeMigrate");
     os.removeObserver(this, "Migration:ItemAfterMigrate");
     os.removeObserver(this, "Migration:ItemError");
     os.removeObserver(this, "Migration:Ended");
+    MigrationUtils.finishMigration();
   },
 
   // 1 - Import Source
   onImportSourcePageShow: function ()
   {
     // Reference to the "From File" radio button 
     var fromfile = null;
 
@@ -113,31 +85,23 @@ var MigrationWizard = {
 
     // The migrator to select. If the "fromfile" migrator is available, use it
     // as the default in case we have no other migrators.
     var selectedMigrator = fromfile;
 
     // Figure out what source apps are are available to import from:
     var group = document.getElementById("importSourceGroup");
     for (var i = 0; i < group.childNodes.length; ++i) {
-      var suffix = group.childNodes[i].id;
-      if (suffix != "nothing" && suffix != "fromfile") {
-        var contractID = kProfileMigratorContractIDPrefix + suffix;
-        try {
-          var migrator = Components.classes[contractID].createInstance(kIMig);
-        }
-        catch (e) {
-          dump("*** invalid contractID =" + contractID + "\n");
-          return;
-        }
-
-        if (migrator.sourceExists) {
+      var migratorKey = group.childNodes[i].id;
+      if (migratorKey != "nothing" && migratorKey != "fromfile") {
+        var migrator = MigrationUtils.getMigrator(migratorKey);
+        if (migrator) {
           // Save this as the first selectable item, if we don't already have
           // one, or if it is the migrator that was passed to us.
-          if (!selectedMigrator || this._source == suffix)
+          if (!selectedMigrator || this._source == migratorKey)
             selectedMigrator = group.childNodes[i];
         } else {
           // Hide this option
           group.childNodes[i].hidden = true;
         }
       }
     }
 
@@ -168,40 +132,38 @@ var MigrationWizard = {
       if(newSource == "fromfile")
         window.opener.fromFile = true;
       document.documentElement.cancel();
       return false;
     }
     
     if (!this._migrator || (newSource != this._source)) {
       // Create the migrator for the selected source.
-      var contractID = kProfileMigratorContractIDPrefix + newSource;
-      this._migrator = Components.classes[contractID].createInstance(kIMig);
+      this._migrator = MigrationUtils.getMigrator(newSource);
 
       this._itemsFlags = kIMig.ALL;
       this._selectedProfile = null;
     }
     this._source = newSource;
       
     // check for more than one source profile
-    if (this._migrator.sourceHasMultipleProfiles)
+    var sourceProfiles = this._migrator.sourceProfiles;    
+    if (sourceProfiles && sourceProfiles.length > 1) {
       this._wiz.currentPage.next = "selectProfile";
+    }
     else {
       if (this._autoMigrate)
         this._wiz.currentPage.next = "homePageImport";
       else if (this._bookmarks)
         this._wiz.currentPage.next = "migrating"
       else
         this._wiz.currentPage.next = "importItems";
 
-      var sourceProfiles = this._migrator.sourceProfiles;
-      if (sourceProfiles && sourceProfiles.length == 1) {
-        var profileName = sourceProfiles.queryElementAt(0, Ci.nsISupportsString);
-        this._selectedProfile = profileName.data;
-      }
+      if (sourceProfiles && sourceProfiles.length == 1)
+        this._selectedProfile = sourceProfiles[0];
       else
         this._selectedProfile = "";
     }
   },
   
   // 2 - [Profile Selection]
   onSelectProfilePageShow: function ()
   {
@@ -215,19 +177,18 @@ var MigrationWizard = {
       profiles.removeChild(profiles.firstChild);
     
     // Note that this block is still reached even if the user chose 'From File'
     // and we canceled the dialog.  When that happens, _migrator will be null.
     if (this._migrator) {
       var sourceProfiles = this._migrator.sourceProfiles;
       for (var i = 0; i < sourceProfiles.length; ++i) {
         var item = document.createElement("radio");
-        var str = sourceProfiles.queryElementAt(i, Ci.nsISupportsString);
-        item.id = str.data;
-        item.setAttribute("label", str.data);
+        item.id = sourceProfiles[i];
+        item.setAttribute("label", sourceProfiles[i]);
         profiles.appendChild(item);
       }
     }
     
     profiles.selectedItem = this._selectedProfile ? document.getElementById(this._selectedProfile) : profiles.firstChild;
   },
   
   onSelectProfilePageRewound: function ()
--- a/browser/components/migration/public/nsIBrowserProfileMigrator.idl
+++ b/browser/components/migration/public/nsIBrowserProfileMigrator.idl
@@ -34,17 +34,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIArray;
 interface nsIProfileStartup;
 
-[scriptable, uuid(5f445759-86a8-4dd3-ab84-4fc5341d9d9d)]
+[scriptable, uuid(44993E0E-74E8-4BEC-9D66-AD8156E0A274)]
 interface nsIBrowserProfileMigrator : nsISupports 
 {
   /**
    * profile items to migrate. use with migrate().
    */
   const unsigned short ALL         = 0x0000;
   const unsigned short SETTINGS    = 0x0001;
   const unsigned short COOKIES     = 0x0002;
@@ -75,25 +75,20 @@ interface nsIBrowserProfileMigrator : ns
 
   /** 
    * Whether or not there is any data that can be imported from this 
    * browser (i.e. whether or not it is installed, and there exists
    * a user profile)
    */
   readonly attribute boolean          sourceExists;
 
-  /** 
-   * Whether or not the import source implementing this interface
-   * has multiple user profiles configured.
-   */
-  readonly attribute boolean          sourceHasMultipleProfiles;
 
   /** 
    * An enumeration of available profiles. If the import source does 
    * not support profiles, this attribute is null.
    */
-  readonly attribute nsIArray         sourceProfiles;
+  readonly attribute jsval            sourceProfiles;
 
   /**
    * The import source homepage.  Returns null if not present/available
    */
   readonly attribute AUTF8String      sourceHomePageURL;
 };
--- a/browser/components/migration/src/ChromeProfileMigrator.js
+++ b/browser/components/migration/src/ChromeProfileMigrator.js
@@ -1,74 +1,34 @@
 /* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=2 sts=2 et
- * ***** 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 the Browser Profile Migrator.
- *
- * 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):
- *   Makoto Kato <m_kato@ga2.so-net.ne.jp> (Original Author)
- *
- * 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 ***** */
+ * This Source Code is subject to the terms of the Mozilla Public License
+ * version 2.0 (the "License"). You can obtain a copy of the License at
+ * http://mozilla.org/MPL/2.0/. */
+
+"use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
-const MIGRATOR = Ci.nsIBrowserProfileMigrator;
 
-const LOCAL_FILE_CID = "@mozilla.org/file/local;1";
 const FILE_INPUT_STREAM_CID = "@mozilla.org/network/file-input-stream;1";
 
-const BUNDLE_MIGRATION = "chrome://browser/locale/migration/migration.properties";
-
 const S100NS_FROM1601TO1970 = 0x19DB1DED53E8000;
 const S100NS_PER_MS = 10;
 
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/Services.jsm");
-Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
-Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/MigrationUtils.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "bookmarksSubfolderTitle", function () {
-  // get "import from google chrome" string for folder
-  let strbundle =
-    Services.strings.createBundle(BUNDLE_MIGRATION);
-  let sourceNameChrome = strbundle.GetStringFromName("sourceNameChrome");
-  return strbundle.formatStringFromName("importedBookmarksFolder",
-                                        [sourceNameChrome],
-                                        1);
-});
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+                                  "resource://gre/modules/PlacesUtils.jsm");
 
 /**
  * Convert Chrome time format to Date object
  *
  * @param   aTime
  *          Chrome time 
  * @return  converted Date object
  * @note    Google Chrome uses FILETIME / 10 as time.
@@ -107,233 +67,240 @@ function insertBookmarkItems(aFolderId, 
         insertBookmarkItems(newFolderId, item.children);
       }
     } catch (e) {
       Cu.reportError(e);
     }
   }
 }
 
-function ChromeProfileMigrator()
-{
+
+function ChromeProfileMigrator() {
+  let chromeUserDataFolder = FileUtils.getDir(
+#ifdef XP_WIN
+    "LocalAppData", ["Google", "Chrome", "User Data"]
+#elifdef XP_MACOSX
+    "ULibDir", ["Application Support", "Google", "Chrome"]
+#else
+    "Home", [".config", "google-chrome"]
+#endif
+    , false);
+  this._chromeUserDataFolder = chromeUserDataFolder.exists() ?
+    chromeUserDataFolder : null;
 }
 
-ChromeProfileMigrator.prototype = {
-  _paths: {
-    bookmarks : null,
-    cookies : null,
-    history : null,
-    prefs : null,
-    userData : null,
-  },
-
-  _homepageURL : null,
-  _replaceBookmarks : false,
-  _sourceProfile: null,
-  _profilesCache: null,
+ChromeProfileMigrator.prototype = Object.create(MigratorPrototype);
 
-  /**
-   * Notify to observers to start migration
-   *
-   * @param   aType
-   *          notification type such as MIGRATOR.BOOKMARKS
-   */
-  _notifyStart : function Chrome_notifyStart(aType)
-  {
-    Services.obs.notifyObservers(null, "Migration:ItemBeforeMigrate", aType);
-    this._pendingCount++;
-  },
+ChromeProfileMigrator.prototype.getResources =
+  function Chrome_getResources(aProfile) {
+    if (this._chromeUserDataFolder) {
+      let profileFolder = this._chromeUserDataFolder.clone();
+      profileFolder.append(aProfile);
+      if (profileFolder.exists()) {
+        let possibleResources = [GetBookmarksResource(profileFolder),
+                                 GetHistoryResource(profileFolder),
+                                 GetCookiesResource(profileFolder)];
+        return [r for each (r in possibleResources) if (r != null)];
+      }
+    }
+    return [];
+  };
 
-  /**
-   * Notify observers that a migration error occured with an item
-   *
-   * @param   aType
-   *          notification type such as MIGRATOR.BOOKMARKS
-   */
-  _notifyError : function Chrome_notifyError(aType)
-  {
-    Services.obs.notifyObservers(null, "Migration:ItemError", aType);
-  },
+Object.defineProperty(ChromeProfileMigrator.prototype, "sourceProfiles", {
+  get: function Chrome_sourceProfiles() {
+    if ("__sourceProfiles" in this)
+      return this.__sourceProfiles;
+
+    if (!this._chromeUserDataFolder)
+      return [];
 
-  /**
-   * Notify to observers to finish migration for item
-   * If all items are finished, it sends migration end notification.
-   *
-   * @param   aType
-   *          notification type such as MIGRATOR.BOOKMARKS
-   */
-  _notifyCompleted : function Chrome_notifyIfCompleted(aType)
-  {
-    Services.obs.notifyObservers(null, "Migration:ItemAfterMigrate", aType);
-    if (--this._pendingCount == 0) {
-      // All items are migrated, so we have to send end notification.
-      Services.obs.notifyObservers(null, "Migration:Ended", null);
-    }
-  },
+    let profiles;
+    try {
+      // Local State is a JSON file that contains profile info.
+      let localState = this._chromeUserDataFolder.clone();
+      localState.append("Local State");
+      if (!localState.exists())
+        throw new Error("Chrome's 'Local State' file does not exist.");
+      if (!localState.isReadable())
+        throw new Error("Chrome's 'Local State' file could not be read.");
 
-  /**
-   * Migrating bookmark items
-   */
-  _migrateBookmarks : function Chrome_migrateBookmarks()
-  {
-    this._notifyStart(MIGRATOR.BOOKMARKS);
-
-    try {
-      PlacesUtils.bookmarks.runInBatchMode({
-        _self : this,
-        runBatched : function (aUserData) {
-          let migrator = this._self;
-          let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-          file.initWithPath(migrator._paths.bookmarks);
-
-          NetUtil.asyncFetch(file, function(aInputStream, aResultCode) {
-            if (!Components.isSuccessCode(aResultCode)) {
-              migrator._notifyCompleted(MIGRATOR.BOOKMARKS);
-              return;
-            }
-
-            // Parse Chrome bookmark file that is JSON format
-            let bookmarkJSON = NetUtil.readInputStreamToString(aInputStream,
-                                                               aInputStream.available(),
-                                                               { charset : "UTF-8" });
-            let roots = JSON.parse(bookmarkJSON).roots;
+      let fstream = Cc[FILE_INPUT_STREAM_CID].createInstance(Ci.nsIFileInputStream);
+      fstream.init(localState, -1, 0, 0);
+      let inputStream = NetUtil.readInputStreamToString(fstream, fstream.available(),
+                                                        { charset: "UTF-8" });
+      let info_cache = JSON.parse(inputStream).profile.info_cache;
+      if (info_cache)
+        profiles = Object.keys(info_cache);
+    } catch (e) {
+      Cu.reportError("Error detecting Chrome profiles: " + e);
+      // If we weren't able to detect any profiles above, fallback to the Default profile.
+      let defaultProfileFolder = this._chromeUserDataFolder.clone();
+      defaultProfileFolder.append("Default");
+      if (defaultProfileFolder.exists())
+        profiles = ["Default"];
+    }
 
-            // Importing bookmark bar items
-            if (roots.bookmark_bar.children &&
-                roots.bookmark_bar.children.length > 0) {
-              // Toolbar
-              let parentId = PlacesUtils.toolbarFolderId;
-              if (!migrator._replaceBookmarks) { 
-                parentId =
-                  PlacesUtils.bookmarks.createFolder(parentId,
-                                                     bookmarksSubfolderTitle,
-                                                     PlacesUtils.bookmarks.DEFAULT_INDEX);
-              }
-              insertBookmarkItems(parentId, roots.bookmark_bar.children);
-            }
+    // Only list profiles from which any data can be imported
+    return this.__sourceProfiles = profiles.filter(function(profileName) {
+      let resources = this.getResources(profileName);
+      return resources && resources.length > 0;
+    }, this);
+  }
+});
 
-            // Importing bookmark menu items
-            if (roots.other.children &&
-                roots.other.children.length > 0) {
-              // Bookmark menu
-              let parentId = PlacesUtils.bookmarksMenuFolderId;
-              if (!migrator._replaceBookmarks) { 
-                parentId =
-                  PlacesUtils.bookmarks.createFolder(parentId,
-                                                     bookmarksSubfolderTitle,
-                                                     PlacesUtils.bookmarks.DEFAULT_INDEX);
-              }
-              insertBookmarkItems(parentId, roots.other.children);
-            }
-
-            migrator._notifyCompleted(MIGRATOR.BOOKMARKS);
-          });
-        }
-      }, null);
-    } catch (e) {
-      Cu.reportError(e);
-      this._notifyError(MIGRATOR.BOOKMARKS);
-      this._notifyCompleted(MIGRATOR.BOOKMARKS);
+Object.defineProperty(ChromeProfileMigrator.prototype, "sourceHomePageURL", {
+  get: function Chrome_sourceHomePageURL() {
+    let prefsFile = this._chromeUserDataFolder.clone();
+    prefsFile.append("Preferences");
+    if (prefsFile.exists()) {
+      // XXX reading and parsing JSON is synchronous.
+      let fstream = Cc[FILE_INPUT_STREAM_CID].
+                    createInstance(Ci.nsIFileInputStream);
+      fstream.init(file, -1, 0, 0);
+      try {
+        return JSON.parse(
+          NetUtil.readInputStreamToString(fstream, fstream.available(),
+                                          { charset: "UTF-8" })
+            ).homepage;
+      }
+      catch(e) {
+        Cu.reportError("Error parsing Chrome's preferences file: " + e);
+      }
     }
-  },
+    return "";
+  }
+});
 
-  /**
-   * Migrating history
-   */
-  _migrateHistory : function Chrome_migrateHistory()
-  {
-    this._notifyStart(MIGRATOR.HISTORY);
+function GetBookmarksResource(aProfileFolder) {
+  let bookmarksFile = aProfileFolder.clone();
+  bookmarksFile.append("Bookmarks");
+  if (!bookmarksFile.exists())
+    return null;
 
-    try {
-      PlacesUtils.history.runInBatchMode({
-        _self : this,
-        runBatched : function (aUserData) {
-          // access sqlite3 database of Chrome's history
-          let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-          file.initWithPath(this._self._paths.history);
-
-          let dbConn = Services.storage.openUnsharedDatabase(file);
-          let stmt = dbConn.createAsyncStatement(
-              "SELECT url, title, last_visit_time, typed_count FROM urls WHERE hidden = 0");
+  return {
+    type: Ci.nsIBrowserProfileMigrator.BOOKMARKS,
 
-          stmt.executeAsync({
-            _asyncHistory : Cc["@mozilla.org/browser/history;1"]
-                            .getService(Ci.mozIAsyncHistory),
-            _db : dbConn,
-            _self : this._self,
-            handleResult : function(aResults) {
-              let places = [];
-              for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) {
-                try {
-                  // if having typed_count, we changes transition type to typed.
-                  let transType = PlacesUtils.history.TRANSITION_LINK;
-                  if (row.getResultByName("typed_count") > 0)
-                    transType = PlacesUtils.history.TRANSITION_TYPED;
-
-                  places.push({
-                    uri: NetUtil.newURI(row.getResultByName("url")),
-                    title: row.getResultByName("title"),
-                    visits: [{
-                      transitionType: transType,
-                      visitDate: chromeTimeToDate(
-                                   row.getResultByName(
-                                     "last_visit_time")) * 1000,
-                    }],
-                  });
-                } catch (e) {
-                  Cu.reportError(e);
+    migrate: function(aCallback) {
+      NetUtil.asyncFetch(bookmarksFile, MigrationUtils.wrapMigrateFunction(
+        function(aInputStream, aResultCode) {
+          if (!Components.isSuccessCode(aResultCode))
+            throw new Error("Could not read Bookmarks file");
+            
+          // Parse Chrome bookmark file that is JSON format
+          let bookmarkJSON = NetUtil.readInputStreamToString(
+            aInputStream, aInputStream.available(), { charset : "UTF-8" });
+          let roots = JSON.parse(bookmarkJSON).roots;
+          PlacesUtils.bookmarks.runInBatchMode({
+            runBatched: function() {
+              // Importing bookmark bar items
+              if (roots.bookmark_bar.children &&
+                  roots.bookmark_bar.children.length > 0) {
+                // Toolbar
+                let parentId = PlacesUtils.toolbarFolderId;
+                if (!MigrationUtils.isStartupMigration) { 
+                  parentId = MigrationUtils.createImportedBookmarksFolder(
+                    "Chrome", parentId);
                 }
+                insertBookmarkItems(parentId, roots.bookmark_bar.children);
               }
 
-              try {
-                this._asyncHistory.updatePlaces(places);
-              } catch (e) {
-                Cu.reportError(e);
+              // Importing bookmark menu items
+              if (roots.other.children &&
+                  roots.other.children.length > 0) {
+                // Bookmark menu
+                let parentId = PlacesUtils.bookmarksMenuFolderId;
+                if (!MigrationUtils.isStartupMigration) { 
+                  parentId = MigrationUtils.createImportedBookmarksFolder(
+                    "Chrome", parentId);
+                }
+                insertBookmarkItems(parentId, roots.other.children);
               }
-            },
+            }
+          }, null);
+        }, aCallback));
+    }
+  };
+}
+
+function GetHistoryResource(aProfileFolder) {
+  let historyFile = aProfileFolder.clone();
+  historyFile.append("History");
+  if (!historyFile.exists())
+    return null;
+
+  return {
+    type: Ci.nsIBrowserProfileMigrator.HISTORY,
+
+    migrate: function(aCallback) {
+      let dbConn = Services.storage.openUnsharedDatabase(historyFile);
+      let stmt = dbConn.createAsyncStatement(
+        "SELECT url, title, last_visit_time, typed_count FROM urls WHERE hidden = 0");
 
-            handleError : function(aError) {
-              Cu.reportError("Async statement execution returned with '" +
-                             aError.result + "', '" + aError.message + "'");
-            },
+      stmt.executeAsync({
+        handleResult : function(aResults) {
+          let places = [];
+          for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) {
+            try {
+              // if having typed_count, we changes transition type to typed.
+              let transType = PlacesUtils.history.TRANSITION_LINK;
+              if (row.getResultByName("typed_count") > 0)
+                transType = PlacesUtils.history.TRANSITION_TYPED;
 
-            handleCompletion : function(aReason) {
-              this._db.asyncClose();
-              this._self._notifyCompleted(MIGRATOR.HISTORY);
+              places.push({
+                uri: NetUtil.newURI(row.getResultByName("url")),
+                title: row.getResultByName("title"),
+                visits: [{
+                  transitionType: transType,
+                  visitDate: chromeTimeToDate(
+                               row.getResultByName(
+                                 "last_visit_time")) * 1000,
+                }],
+              });
+            } catch (e) {
+              Cu.reportError(e);
             }
-          });
-          stmt.finalize();
+          }
+
+          try {
+            PlacesUtils.asyncHistory.updatePlaces(places);
+          } catch (e) {
+            Cu.reportError(e);
+          }
+        },
+
+        handleError : function(aError) {
+          Cu.reportError("Async statement execution returned with '" +
+                         aError.result + "', '" + aError.message + "'");
+        },
+
+        handleCompletion : function(aReason) {
+          dbConn.asyncClose();
+          aCallback(aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED);
         }
-      }, null);
-    } catch (e) {
-      Cu.reportError(e);
-      this._notifyError(MIGRATOR.HISTORY);
-      this._notifyCompleted(MIGRATOR.HISTORY);
+      });
+      stmt.finalize();
     }
-  },
+  };
+}
 
-  /**
-   * Migrating cookies
-   */
-  _migrateCookies : function Chrome_migrateCookies()
-  {
-    this._notifyStart(MIGRATOR.COOKIES);
+function GetCookiesResource(aProfileFolder) {
+  let cookiesFile = aProfileFolder.clone();
+  cookiesFile.append("Cookies");
+  if (!cookiesFile.exists())
+    return null;
 
-    try {
-      // Access sqlite3 database of Chrome's cookie
-      let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-      file.initWithPath(this._paths.cookies);
+  return {
+    type: Ci.nsIBrowserProfileMigrator.COOKIES,
 
-      let dbConn = Services.storage.openUnsharedDatabase(file);
+    migrate: function(aCallback) {
+      let dbConn = Services.storage.openUnsharedDatabase(cookiesFile);
       let stmt = dbConn.createAsyncStatement(
           "SELECT host_key, path, name, value, secure, httponly, expires_utc FROM cookies");
 
       stmt.executeAsync({
-        _db : dbConn,
-        _self : this,
         handleResult : function(aResults) {
           for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) {
             let host_key = row.getResultByName("host_key");
             if (host_key.match(/^\./)) {
               // 1st character of host_key may be ".", so we have to remove it
               host_key = host_key.substr(1);
             }
 
@@ -355,251 +322,22 @@ ChromeProfileMigrator.prototype = {
         },
 
         handleError : function(aError) {
           Cu.reportError("Async statement execution returned with '" +
                          aError.result + "', '" + aError.message + "'");
         },
 
         handleCompletion : function(aReason) {
-          this._db.asyncClose();
-          this._self._notifyCompleted(MIGRATOR.COOKIES);
+          dbConn.asyncClose();
+          aCallback(aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED);
         },
       });
       stmt.finalize();
-    } catch (e) {
-      Cu.reportError(e);
-      this._notifyError(MIGRATOR.COOKIES);
-      this._notifyCompleted(MIGRATOR.COOKIES);
     }
-  },
-
-  /**
-   * nsIBrowserProfileMigrator interface implementation
-   */
-
-  /**
-   * Let's migrate all items
-   *
-   * @param   aItems
-   *          list of data items to migrate.
-   * @param   aStartup
-   *          non-null if called during startup.
-   * @param   aProfile
-   *          profile directory name to migrate
-   */
-  migrate : function Chrome_migrate(aItems, aStartup, aProfile)
-  {
-    if (aStartup) {
-      aStartup.doStartup();
-      this._replaceBookmarks = true;
-    }
-
-    this._sourceProfile = aProfile;
-
-    Services.obs.notifyObservers(null, "Migration:Started", null);
-
-    // Reset panding count.  If this count becomes 0, "Migration:Ended"
-    // notification is sent
-    this._pendingCount = 1;
-
-    if (aItems & MIGRATOR.HISTORY)
-      this._migrateHistory();
-
-    if (aItems & MIGRATOR.COOKIES)
-      this._migrateCookies();
-
-    if (aItems & MIGRATOR.BOOKMARKS)
-      this._migrateBookmarks();
-
-    if (--this._pendingCount == 0) {
-      // When async imports are immeditelly completed unfortunately,
-      // this will be called.
-      // Usually, this notification is sent by _notifyCompleted()
-      Services.obs.notifyObservers(null, "Migration:Ended", null);
-    }
-  },
-
-  /**
-   * return supported migration types
-   *
-   * @param   aProfile
-   *          directory name of the profile
-   * @param   aDoingStartup
-   *          non-null if called during startup.
-   * @return  supported migration types
-   */
-  getMigrateData: function Chrome_getMigrateData(aProfile, aDoingStartup)
-  {
-    this._sourceProfile = aProfile;
-    let chromeProfileDir = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-    chromeProfileDir.initWithPath(this._paths.userData + aProfile);
-
-    let result = 0;
-    if (!chromeProfileDir.exists() || !chromeProfileDir.isReadable())
-      return result;
-
-    // bookmark and preference are JSON format
-
-    try {
-      let file = chromeProfileDir.clone();
-      file.append("Bookmarks");
-      if (file.exists()) {
-        this._paths.bookmarks = file.path;
-        result += MIGRATOR.BOOKMARKS;
-      }
-    } catch (e) {
-      Cu.reportError(e);
-    }
-
-    if (!this._paths.prefs) {
-      let file = chromeProfileDir.clone();
-      file.append("Preferences");
-      this._paths.prefs = file.path;
-    }
-
-    // history and cookies are SQLite database
-
-    try {
-      let file = chromeProfileDir.clone();
-      file.append("History");
-      if (file.exists()) {
-        this._paths.history = file.path;
-        result += MIGRATOR.HISTORY;
-      }
-    } catch (e) {
-      Cu.reportError(e);
-    }
-
-    try {
-      let file = chromeProfileDir.clone();
-      file.append("Cookies");
-      if (file.exists()) {
-        this._paths.cookies = file.path;
-        result += MIGRATOR.COOKIES;
-      }
-    } catch (e) {
-      Cu.reportError(e);
-    }
-
-    return result;
-  },
+  }
+}
 
-  /**
-   * Whether we support migration of Chrome
-   *
-   * @return true if supported
-   */
-  get sourceExists()
-  {
-#ifdef XP_WIN
-    this._paths.userData = Services.dirsvc.get("LocalAppData", Ci.nsIFile).path +
-                            "\\Google\\Chrome\\User Data\\";
-#elifdef XP_MACOSX
-    this._paths.userData = Services.dirsvc.get("Home", Ci.nsIFile).path +
-                            "/Library/Application Support/Google/Chrome/";
-#else
-    this._paths.userData = Services.dirsvc.get("Home", Ci.nsIFile).path +
-                            "/.config/google-chrome/";
-#endif
-    let result = 0;
-    try {
-      let userDataDir = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-      userDataDir.initWithPath(this._paths.userData);
-      if (!userDataDir.exists() || !userDataDir.isReadable())
-        return false;
-
-      let profiles = this.sourceProfiles;
-      if (profiles.length < 1)
-        return false;
-
-      // check that we can actually get data from the first profile
-      result = this.getMigrateData(profiles.queryElementAt(0, Ci.nsISupportsString), false);
-    } catch (e) {
-      Cu.reportError(e);
-    }
-    return result > 0;
-  },
-
-  get sourceHasMultipleProfiles()
-  {
-    return this.sourceProfiles.length > 1;
-  },
-
-  get sourceProfiles()
-  {
-    let profiles = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-    try {
-      if (!this._profilesCache) {
-        let localState = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-        // Local State is a JSON file that contains profile info.
-        localState.initWithPath(this._paths.userData + "Local State");
-        if (!localState.exists())
-          throw new Components.Exception("Chrome's 'Local State' file does not exist.",
-                                         Cr.NS_ERROR_FILE_NOT_FOUND);
-        if (!localState.isReadable())
-          throw new Components.Exception("Chrome's 'Local State' file could not be read.",
-                                         Cr.NS_ERROR_FILE_ACCESS_DENIED);
-        let fstream = Cc[FILE_INPUT_STREAM_CID].createInstance(Ci.nsIFileInputStream);
-        fstream.init(localState, -1, 0, 0);
-        let inputStream = NetUtil.readInputStreamToString(fstream, fstream.available(),
-                                                          { charset: "UTF-8" });
-        this._profilesCache = JSON.parse(inputStream).profile.info_cache;
-      }
-
-      for (let index in this._profilesCache) {
-        let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
-        str.data = index;
-        profiles.appendElement(str, false);
-      }
-    } catch (e) {
-      Cu.reportError("Error detecting Chrome profiles: " + e);
-      // if we weren't able to detect any profiles above, fallback to the Default profile.
-      if (profiles.length < 1) {
-        let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
-        // the default profile name is "Default"
-        str.data = "Default";
-        profiles.appendElement(str, false);
-      }
-    }
-    return profiles;
-  },
-
-  /**
-   * Return home page URL
-   *
-   * @return  home page URL
-   */
-  get sourceHomePageURL()
-  {
-    try  {
-      if (this._homepageURL)
-        return this._homepageURL;
-
-      if (!this._paths.prefs)
-        this.getMigrateData(this._sourceProfile, false);
-
-      // XXX reading and parsing JSON is synchronous.
-      let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-      file.initWithPath(this._paths.prefs);
-      let fstream = Cc[FILE_INPUT_STREAM_CID].
-                    createInstance(Ci.nsIFileInputStream);
-      fstream.init(file, -1, 0, 0); 
-      this._homepageURL = JSON.parse(
-        NetUtil.readInputStreamToString(fstream, fstream.available(),
-                                        { charset: "UTF-8" })).homepage;
-      return this._homepageURL;
-    } catch (e) {
-      Cu.reportError(e);
-    }
-    return "";
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIBrowserProfileMigrator
-  ]),
-
-  classDescription: "Chrome Profile Migrator",
-  contractID: "@mozilla.org/profile/migrator;1?app=browser&type=chrome",
-  classID: Components.ID("{4cec1de4-1671-4fc3-a53e-6c539dc77a26}")
-};
+ChromeProfileMigrator.prototype.classDescription = "Chrome Profile Migrator";
+ChromeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=chrome";
+ChromeProfileMigrator.prototype.classID = Components.ID("{4cec1de4-1671-4fc3-a53e-6c539dc77a26}");
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeProfileMigrator]);
--- a/browser/components/migration/src/Makefile.in
+++ b/browser/components/migration/src/Makefile.in
@@ -54,22 +54,26 @@ CPPSRCS += nsIEProfileMigrator.cpp \
            nsBrowserProfileMigratorUtils.cpp \
            $(NULL)
 endif
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += nsSafariProfileMigrator.cpp \
            nsBrowserProfileMigratorUtils.cpp \
            $(NULL)
-endif            
+endif
 
 EXTRA_PP_COMPONENTS = \
   ProfileMigrator.js \
   ChromeProfileMigrator.js \
   FirefoxProfileMigrator.js \
   $(NULL)
 
 EXTRA_COMPONENTS = \
 	BrowserProfileMigrators.manifest \
 	$(NULL)
 
+EXTRA_PP_JS_MODULES = \
+	MigrationUtils.jsm \
+	$(NULL)
+
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/browser/components/migration/src/MigrationUtils.jsm
@@ -0,0 +1,453 @@
+/* This Source Code is subject to the terms of the Mozilla Public License
+ * version 2.0 (the "License"). You can obtain a copy of the License at
+ * http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+let EXPORTED_SYMBOLS = ["MigrationUtils", "MigratorPrototype"];
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Dict",
+                                  "resource://gre/modules/Dict.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+                                  "resource://gre/modules/PlacesUtils.jsm");
+
+let gMigrators = null;
+let gProfileStartup = null;
+
+/**
+ * Shared prototype for migrators, implementing nsIBrowserProfileMigrator.
+ *
+ * To implement a migrator:
+ * 1. Import this module.
+ * 2. Create the prototype for the migrator, extending MigratorPrototype.
+ *    Namely: MosaicMigrator.prototype = Object.create(MigratorPrototype);
+ * 3. Set classDescription, contractID and classID for your migrator, and set
+ *    NSGetFactory appropriately.
+ * 4. If the migrator supports multiple profiles, override the sourceProfiles
+ *    Here we default for single-profile migrator.
+ * 5. Implement getResources(aProfile) (see below).
+ * 6. If the migrator supports reading the home page of the source browser,
+ *    override |sourceHomePageURL| getter.
+ * 7. For startup-only migrators, override |startupOnlyMigrator|.
+ */
+let MigratorPrototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserProfileMigrator]),
+
+  /**
+   * OVERRIDE IF AND ONLY IF the source supports multiple profiles.
+   *
+   * Returns array of profiles (by names) from which data may be imported.
+   *
+   * Only profiles from which data can be imported should be listed.  Otherwise
+   * the behavior of the migration wizard isn't well-defined.
+   *
+   * For a single-profile source (e.g. safari, ie), this returns null,
+   * and not an empty array.  That is the default implementation.
+   */
+  get sourceProfiles() null,
+
+  /**
+   * MUST BE OVERRIDDEN.
+   *
+   * Returns an array of "migration resources" objects for the given profile,
+   * or for the "default" profile, if the migrator does not support multiple
+   * profiles.
+   *
+   * Each migration resource should provide:
+   * - a |type| getter, retunring any of the migration types (see
+   *   nsIBrowserProfileMigrator).
+   *
+   * - a |migrate| method, taking a single argument, aCallback(bool success),
+   *   for migrating the data for this resource.  It may do its job
+   *   synchronously or asynchronously.  Either way, it must call
+   *   aCallback(bool aSuccess) when it's done.  In the case of an exception
+   *   thrown from |migrate|, it's taken as if aCallback(false) is called.
+   *
+   *   Note: In the case of a simple asynchronous implementation, you may find
+   *   MigrationUtils.wrapMigrateFunction handy for handling aCallback easily.
+   *
+   * For each migration type listed in nsIBrowserProfileMigrator, multiple
+   * migration resources may be provided.  This practice is useful when the
+   * data for a certain migration type is independently stored in few
+   * locations.  For example, the mac version of Safari stores its "reading list"
+   * bookmarks in a separate property list.
+   *
+   * Note that the importation of a particular migration type is reported as
+   * successful if _any_ of its resources succeeded to import (that is, called,
+   * |aCallback(true)|).  However, completion-status for a particular migration
+   * type is reported to the UI only once all of its migrators have called
+   * aCallback.
+   *
+   * @note  The returned array should only include resources from which data
+   *        can be imported.  So, for example, before adding a resource for the
+   *        BOOKMARKS migration type, you should check if you should check that the
+   *        bookmarks file exists.
+   *
+   * @param aProfile
+   *        The profile from which data may be imported, or an empty string
+   *        in the case of a single-profile migrator.
+   *        In the case of multiple-profiles migrator, it is guaranteed that
+   *        aProfile is a value returned by the sourceProfiles getter (see
+   *        above).
+   */
+  getResources: function MP_getResources(aProfile) {
+    throw new Error("getResources must be overridden");
+  },
+
+  /**
+   * OVERRIDE IF AND ONLY IF the migrator is a startup-only migrator (For now,
+   * that is just the Firefox migrator, see bug 737381).  Default: false.
+   *
+   * Startup-only migrators are different in two ways:
+   * - they may only be used during startup.
+   * - the user-profile is half baked during migration.  The folder exists,
+   *   but it's only accessible through MigrationUtils.profileStartup.
+   *   The migrator can call MigrationUtils.profileStartup.doStartup
+   *   at any point in order to initialize the profile.
+   */
+  get startupOnlyMigrator() false,
+
+  /**
+   * OVERRIDE IF AND ONLY IF your migrator supports importing the homepage.
+   * @see nsIBrowserProfileMigrator
+   */
+  get sourceHomePageURL() "",
+
+  /**
+   * DO NOT OVERRIDE - After deCOMing migration, the UI will just call
+   * getResources.
+   *
+   * @see nsIBrowserProfileMigrator
+   */
+  getMigrateData: function MP_getMigrateData(aProfile) {
+    let types = [r.type for each (r in this._getMaybeCachedResources(aProfile))];
+    return types.reduce(function(a, b) a |= b, 0);
+  },
+
+  /**
+   * DO NOT OVERRIDE - After deCOMing migration, the UI will just call
+   * migrate for each resource.
+   *
+   * @see nsIBrowserProfileMigrator
+   */
+  migrate: function MP_migrate(aItems, aStartup, aProfile) {
+    // Not using aStartup because it's going away soon.
+    if (MigrationUtils.isStartupMigration && !this.startupOnlyMigrator)
+      MigrationUtils.profileStartup.doStartup();
+
+    let resources = this._getMaybeCachedResources(aProfile);
+    if (resources.length == 0)
+      throw new Error("migrate called for a non-existent source");
+
+    if (aItems != Ci.nsIBrowserProfileMigrator.ALL)
+      resources = [r for each (r in resources) if (aItems & r.type)];
+
+    // TODO: use Map (for the items) and Set (for the resources)
+    // once they are iterable.
+    let resourcesGroupedByItems = new Dict();
+    resources.forEach(function(resource) {
+      if (resourcesGroupedByItems.has(resource.type))
+        resourcesGroupedByItems.get(resource.type).push(resource);
+      else
+        resourcesGroupedByItems.set(resource.type, [resource]);
+    });
+
+    if (resourcesGroupedByItems.count == 0)
+      throw new Error("No items to import");
+
+    let notify = function(aMsg, aItemType) {
+      Services.obs.notifyObservers(null, aMsg, aItemType);
+    }
+
+    notify("Migration:Started");
+    resourcesGroupedByItems.listkeys().forEach(function(migrationType) {
+      let migrationTypeA = migrationType;
+      let itemResources = resourcesGroupedByItems.get(migrationType);
+      notify("Migration:ItemBeforeMigrate", migrationType);
+
+      let itemSuccess = false;
+      itemResources.forEach(function(resource) {
+        let resourceDone = function(aSuccess) {
+          let resourceIndex = itemResources.indexOf(resource);
+          if (resourceIndex != -1) {
+            itemResources.splice(resourceIndex, 1);
+            itemSuccess |= aSuccess;
+            if (itemResources.length == 0) {
+              resourcesGroupedByItems.del(migrationType);
+              notify(itemSuccess ?
+                     "Migration:ItemAfterMigrate" : "Migration:ItemError",
+                     migrationType);
+              if (resourcesGroupedByItems.count == 0)
+                notify("Migration:Ended");
+            }
+          }
+        };
+
+        Services.tm.mainThread.dispatch(function() {
+          // If migrate throws, an error occurred, and the callback
+          // (itemMayBeDone) might haven't been called.
+          try {
+            resource.migrate(resourceDone);
+          }
+          catch(ex) {
+            Cu.reportError(ex);
+            resourceDone(false);
+          }
+        }, Ci.nsIThread.DISPATCH_NORMAL);
+      });
+    });
+  },
+
+  /**
+   * DO NOT OVERRIDE - After deCOMing migration, this code
+   * won't be part of the migrator itself.
+   *
+   * @see nsIBrowserProfileMigrator
+   */
+  get sourceExists() {
+    if (this.startupOnlyMigrator && !MigrationUtils.isStartupMigration)
+      return false;
+
+    // For a single-profile source, check if any data is available.
+    // For multiple-profiles source, make sure that at least one
+    // profile is available.
+    let profiles = this.sourceProfiles;
+    return (!profiles && this.getResources("")) ||
+           (profiles && profiles.length > 0);
+  },
+
+  /*** PRIVATE STUFF - DO NOT OVERRIDE ***/
+  _getMaybeCachedResources: function PMB__getMaybeCachedResources(aProfile) {
+    if (this._resourcesByProfile) {
+      if (aProfile in this._resourcesByProfile)
+        return this._resourcesByProfile[aProfile];
+    }
+    else {
+      this._resourcesByProfile = { };
+    }
+    return this._resourcesByProfile[aProfile] = this.getResources(aProfile);
+  }
+};
+
+let MigrationUtils = Object.freeze({
+  /**
+   * Helper for implementing simple asynchronous cases of migration resources'
+   * |migrate(aCallback)| (see MigratorPrototype).  If your |migrate| method
+   * just waits for some file to be read, for example, and then migrates
+   * everything right away, you can wrap the async-function with this helper
+   * and not worry about notifying the callback.
+   *
+   * For example, instead of writing:
+   * setTimeout(function() {
+   *   try {
+   *     ....
+   *     aCallback(true);
+   *   }
+   *   catch() {
+   *     aCallback(false);
+   *   }
+   * }, 0);
+   *
+   * You may write:
+   * setTimeout(MigrationUtils.wrapMigrateFunction(function() {
+   *   if (importingFromMosaic)
+   *     throw Cr.NS_ERROR_UNEXPECTED;
+   * }, aCallback), 0);
+   *
+   * ... and aCallback will be called with aSuccess=false when importing
+   * from Mosaic, or with aSuccess=true otherwise.
+   *
+   * @param aFunction
+   *        the function that will be called sometime later.  If aFunction
+   *        throws when it's called, aCallback(false) is called, otherwise
+   *        aCallback(true) is called.
+   * @param aCallback
+   *        the callback function passed to |migrate|.
+   * @return the wrapped function.
+   */
+  wrapMigrateFunction: function MU_wrapMigrateFunction(aFunction, aCallback) {
+    return function() {
+      let success = false;
+      try {
+        aFunction.apply(null, arguments);
+        success = true;
+      }
+      catch(ex) {
+        Cu.reportError(ex);
+      }
+      // Do not change this to call aCallback directly in try try & catch
+      // blocks, because if aCallback throws, we may end up calling aCallback
+      // twice.
+      aCallback(success);
+    }
+  },
+
+  /**
+   * Helper for creating a folder for imported bookmarks from a particular
+   * migration source.  The folder is created at the end of the given folder.
+   *
+   * @param aSourceNameStr
+   *        the source name (first letter capitalized).  This is used
+   *        for reading the localized source name from the migration
+   *        bundle (e.g. if aSourceNameStr is Mosaic, this will try to read
+   *        sourceNameMosaic from the migration bundle).
+   * @param aParentId
+   *        the item-id of the folder in which the new folder should be
+   *        created.
+   * @return the item-id of the new folder.
+   */
+  createImportedBookmarksFolder:
+  function MU_createImportedBookmarksFolder(aSourceNameStr, aParentId) {
+    let bundle = Services.strings.createBundle(
+     "chrome://browser/locale/migration/migration.properties");
+    let sourceName = bundle.GetStringFromName("sourceName" + aSourceNameStr);
+    let folderName = bundle.formatStringFromName("importedBookmarksFolder",
+                                                 [sourceName], 1);
+    return PlacesUtils.bookmarks.createFolder(
+      aParentId, folderName, PlacesUtils.bookmarks.DEFAULT_INDEX);
+  },
+
+  get _migrators() gMigrators ? gMigrators : gMigrators = new Dict(),
+
+  /*
+   * Returns the migrator for the given source, if any data is available
+   * for this source, or null otherwise.
+   *
+   * @param aKey internal name of the migration source.
+   *             Supported values: ie (windows),
+   *                               safari (mac/windows),
+   *                               chrome (mac/windows/linux).
+   *
+   * If null is returned,  either no data can be imported
+   * for the given migrator, or aMigratorKey is invalid  (e.g. ie on mac,
+   * or mosaic everywhere).  This method should be used rather than direct
+   * getService for future compatibility (see bug 718280).
+   *
+   * @return profile migrator implementing nsIBrowserProfileMigrator, if it can
+   *         import any data, null otherwise.
+   */
+  getMigrator: function MU_getMigrator(aKey) {
+    let migrator = null;
+    if (this._migrators.has(aKey)) {
+      migrator = this._migrators.get(aKey);
+    }
+    else {
+      try {
+        migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=" +
+                      aKey].createInstance(Ci.nsIBrowserProfileMigrator);
+      }
+      catch(ex) {
+        Cu.reportError("Could not get migrator '" + aKey + "' (" + ex + ")");
+      }
+      this._migrators.set(aKey, migrator);
+    }
+
+    return migrator && migrator.sourceExists ? migrator : null;
+  },
+
+  // Whether or not we're in the process of startup migration
+  get isStartupMigration() gProfileStartup != null,
+
+  /**
+   * In the case of startup migration, this is set to the nsIProfileStartup
+   * instance passed to ProfileMigrator's migrate.
+   *
+   * @see showMigrationWizard
+   */
+  get profileStartup() gProfileStartup,
+
+  /**
+   * Start the migration wizard.
+   *
+   * Supplying a migrator will result in automatic migration. You should
+   * make sure that the migrator for this key exists before passing
+   * it (use getMigrator).
+   *
+   * @param [optional] aOpener
+   *        the window to which the wizard window is associated.
+   * @param [optional] aProfileStartup
+   *        @see nsIProfileMigrator and nsIProfileStartup.  This is used
+   *        for initializing the profile during migration and for indicating
+   *        startup-migration
+   * @param [optional] aKey
+   *        A migration-source internal name (@see getMigrator) for an existent
+   *        source.  This is ignored if aProfileStartup is not set, and required
+   *        if it is.
+   * @param [optional] aSkipImportSourcePage
+   *        Whether or not to skip the migration-source selection page in the
+   *        wizard (ignored if aProfileStartup is not set).  Default: false.
+   *
+   * @throws if aKey is set to an invalid or non-existent migration source.
+   * @note aParentWindow is ignored on OS X, because wizards are not modal
+   *       on this platform.
+   */
+  showMigrationWizard:
+  function MU_showMigrationWizard(aOpener, aProfileStartup, aMigratorKey,
+                                  aSkipImportSourcePage) {
+    let features = "chrome,dialog,modal,centerscreen,titlebar";
+    let params = null;
+    if (!aProfileStartup) {
+#ifdef XP_MACOSX
+      let win = Services.wm.getMostRecentWindow("Browser:MigrationWizard");
+      if (win) {
+        win.focus();
+        return;
+      }
+      features = "centerscreen,chrome,resizable=no";
+#endif
+    }
+    else {
+      if (!aMigratorKey)
+        throw new Error("aMigratorKey must be set for startup migration");
+
+      let migrator = this.getMigrator(aMigratorKey);
+      if (!migrator) {
+        throw new Error("startMigration was asked to open auto-migrate from a non-existent source: " +
+                        aMigratorKey);
+      }
+      else {
+        gProfileStartup = aProfileStartup;
+      }
+      
+      // By opening the wizard with a supplied migrator, it will
+      // automatically migrate from it.
+      params = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+      let keyCSTR = Cc["@mozilla.org/supports-cstring;1"].
+                    createInstance(Ci.nsISupportsCString);
+      keyCSTR.data = aMigratorKey;
+      let skipImportSourcePageBool = Cc["@mozilla.org/supports-PRBool;1"].
+                                     createInstance(Ci.nsISupportsPRBool);
+      params.appendElement(keyCSTR, false);
+      params.appendElement(migrator, false);
+      params.appendElement(aProfileStartup, false);
+
+      if (aSkipImportSourcePage === true) {
+        let wrappedBool = Cc["@mozilla.org/supports-PRBool;1"].
+                          createInstance(Ci.nsISupportsPRBool);
+        wrappedBool.data = true;
+        params.appendElement(wrappedBool);
+      }
+    }
+
+    Services.ww.openWindow(null,
+                           "chrome://browser/content/migration/migration.xul",
+                           "_blank",
+                           features,
+                           params);
+  },
+
+  /**
+   * Cleans up references to migrators and nsIProfileInstance instances.
+   */
+  finishMigration: function MU_finishMigration() {
+    gMigrators = null;
+    gProfileStartup = null;
+  }
+});
--- a/browser/components/migration/src/ProfileMigrator.js
+++ b/browser/components/migration/src/ProfileMigrator.js
@@ -4,75 +4,44 @@
 
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/MigrationUtils.jsm");
 
 function ProfileMigrator() {
 }
 
 ProfileMigrator.prototype = {
   migrate: function PM_migrate(aStartup, aKey) {
-    // By opening the wizard with a supplied migrator, it will automatically
-    // migrate from it.
-    let key = null, migrator = null;
-    let skipImportSourcePage = Cc["@mozilla.org/supports-PRBool;1"]
-                                 .createInstance(Ci.nsISupportsPRBool);
-    if (aKey) {
-      key = aKey;
-      migrator = this._getMigratorIfSourceExists(key);
-      if (!migrator) {
+    let key = aKey;
+    let skipSourcePage = false;
+    if (key.length > 0) {
+      if (!MigrationUtils.getMigrator(key)) {
         Cu.reportError("Invalid migrator key specified or source does not exist.");
-        return;
+        return;   
       }
+
       // If the migrator was passed to us from the caller, use that migrator
       // and skip the import source page.
-      skipImportSourcePage.data = true;
-    } else {
-      [key, migrator] = this._getDefaultMigrator();
+      skipSourcePage = true;
     }
-    if (!key)
-        return;
-
-    let params = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-    params.appendElement(this._toCString(key), false);
-    params.appendElement(migrator, false);
-    params.appendElement(aStartup, false);
-    params.appendElement(skipImportSourcePage, false);
+    else {
+      key = this._getDefaultMigrator();
+    }
 
-    Services.ww.openWindow(null,
-                           "chrome://browser/content/migration/migration.xul",
-                           "_blank",
-                           "chrome,dialog,modal,centerscreen,titlebar",
-                           params);
-  },
+    if (!key)
+      return;
 
-  _toCString: function PM__toCString(aStr) {
-    let cstr = Cc["@mozilla.org/supports-cstring;1"].
-               createInstance(Ci.nsISupportsCString);
-    cstr.data = aStr;
-    return cstr;
-  },
-
-  _getMigratorIfSourceExists: function PM__getMigratorIfSourceExists(aKey) {
-    try {
-      let cid = "@mozilla.org/profile/migrator;1?app=browser&type=" + aKey;
-      let migrator = Cc[cid].createInstance(Ci.nsIBrowserProfileMigrator);
-      if (migrator.sourceExists)
-        return migrator;
-    } catch (ex) {
-      Cu.reportError("Could not get migrator: " + ex);
-    }
-    return null;
+    MigrationUtils.showMigrationWizard(null, aStartup, key, skipSourcePage);
   },
 
   // We don't yet support checking for the default browser on all platforms,
   // needless to say we don't have migrators for all browsers.  Thus, for each
   // platform, there's a fallback list of migrators used in these cases.
   _PLATFORM_FALLBACK_LIST:
 #ifdef XP_WIN
      ["ie", "chrome", /* safari */],
@@ -139,22 +108,22 @@ ProfileMigrator.prototype = {
 
     // If we found the default browser and we have support for that browser,
     // make sure to check it before any other browser, by moving it to the head
     // of the array.
     if (defaultBrowser)
       migratorsOrdered.sort(function(a, b) b == defaultBrowser ? 1 : 0);
 
     for (let i = 0; i < migratorsOrdered.length; i++) {
-      let migrator = this._getMigratorIfSourceExists(migratorsOrdered[i]);
+      let migrator = MigrationUtils.getMigrator(migratorsOrdered[i]);
       if (migrator)
-        return [migratorsOrdered[i], migrator];
+        return migratorsOrdered[i];
     }
 
-    return ["", null];
+    return "";
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIProfileMigrator]),
   classDescription: "Profile Migrator",
   contractID: "@mozilla.org/toolkit/profile-migrator;1",
   classID: Components.ID("6F8BB968-C14F-4D6F-9733-6C6737B35DCE")
 };
 
--- a/browser/components/migration/src/nsIEProfileMigrator.cpp
+++ b/browser/components/migration/src/nsIEProfileMigrator.cpp
@@ -93,16 +93,17 @@
 #include "nsINavBookmarksService.h"
 #include "nsBrowserCompsCID.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
 #include "nsToolkitCompsCID.h"
 #include "nsUnicharUtils.h"
 #include "nsIWindowsRegKey.h"
 #include "nsISupportsPrimitives.h"
+#include "jsapi.h"
 
 #define kNotFound -1
 
 #define TRIDENTPROFILE_BUNDLE       "chrome://browser/locale/migration/migration.properties"
 
 #define REGISTRY_IE_MAIN_KEY \
   NS_LITERAL_STRING("Software\\Microsoft\\Internet Explorer\\Main")
 #define REGISTRY_IE_TYPEDURL_KEY \
@@ -475,26 +476,19 @@ nsIEProfileMigrator::GetSourceExists(boo
 {
   // IE always exists. 
   *aResult = true;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsIEProfileMigrator::GetSourceHasMultipleProfiles(bool* aResult)
+nsIEProfileMigrator::GetSourceProfiles(JS::Value* aResult)
 {
-  *aResult = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsIEProfileMigrator::GetSourceProfiles(nsIArray** aResult)
-{
-  *aResult = nsnull;
+  *aResult = JSVAL_NULL;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsIEProfileMigrator::GetSourceHomePageURL(nsACString& aResult)
 {
   nsCOMPtr<nsIWindowsRegKey> regKey = 
     do_CreateInstance("@mozilla.org/windows-registry-key;1");
--- a/browser/components/migration/src/nsSafariProfileMigrator.cpp
+++ b/browser/components/migration/src/nsSafariProfileMigrator.cpp
@@ -59,16 +59,17 @@
 #include "nsIRDFService.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
 #include "nsISupportsPrimitives.h"
 #include "nsSafariProfileMigrator.h"
 #include "nsToolkitCompsCID.h"
 #include "nsNetUtil.h"
 #include "nsTArray.h"
+#include "jsapi.h"
 
 #include "mozilla/Util.h"
 
 #include <Carbon/Carbon.h>
 
 #define SAFARI_PREFERENCES_FILE_NAME      NS_LITERAL_STRING("com.apple.Safari.plist")
 #define SAFARI_BOOKMARKS_FILE_NAME        NS_LITERAL_STRING("Bookmarks.plist")
 #define SAFARI_HISTORY_FILE_NAME          NS_LITERAL_STRING("History.plist")
@@ -192,27 +193,19 @@ nsSafariProfileMigrator::GetSourceExists
   GetMigrateData(nsnull, false, &data);
 
   *aResult = data != 0;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSafariProfileMigrator::GetSourceHasMultipleProfiles(bool* aResult)
+nsSafariProfileMigrator::GetSourceProfiles(JS::Value* aResult)
 {
-  // Safari only has one profile per-user.
-  *aResult = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSafariProfileMigrator::GetSourceProfiles(nsIArray** aResult)
-{
-  *aResult = nsnull;
+  *aResult = JSVAL_NULL;
   return NS_OK;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // nsSafariProfileMigrator
 
 CFPropertyListRef CopyPListFromFile(nsILocalFile* aPListFile)
 {
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -35,16 +35,18 @@
  * 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 ***** */
 
+Components.utils.import("resource://gre/modules/MigrationUtils.jsm");
+
 var PlacesOrganizer = {
   _places: null,
   _content: null,
 
   // IDs of fields from editBookmarkOverlay that should be hidden when infoBox
   // is minimal. IDs should be kept in sync with the IDs of the elements
   // observing additionalInfoBroadcaster.
   _additionalInfoFields: [
@@ -380,30 +382,17 @@ var PlacesOrganizer = {
     return PlacesUtils.asQuery(this._content.result.root).getQueries();
   },
 
   /**
    * Show the migration wizard for importing passwords,
    * cookies, history, preferences, and bookmarks.
    */
   importFromBrowser: function PO_importFromBrowser() {
-#ifdef XP_MACOSX
-    // On Mac, the window is not modal
-    let win = Services.wm.getMostRecentWindow("Browser:MigrationWizard");
-    if (win) {
-      win.focus();
-      return;
-    }
-
-    let features = "centerscreen,chrome,resizable=no";
-#else
-    let features = "modal,centerscreen,chrome,resizable=no";
-#endif
-    window.openDialog("chrome://browser/content/migration/migration.xul",
-                      "migration", features);
+    MigrationUtils.showMigrationWizard(window);
   },
 
   /**
    * Open a file-picker and import the selected file into the bookmarks store
    */
   importFromFile: function PO_importFromFile() {
     var fp = Cc["@mozilla.org/filepicker;1"].
              createInstance(Ci.nsIFilePicker);
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -422,23 +422,25 @@
 
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
 
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
+#ifdef MOZ_SAFE_BROWSING
 @BINPATH@/components/nsSafebrowsingApplication.manifest
 @BINPATH@/components/nsSafebrowsingApplication.js
 @BINPATH@/components/nsURLClassifier.manifest
 @BINPATH@/components/nsUrlClassifierHashCompleter.js
 @BINPATH@/components/nsUrlClassifierListManager.js
 @BINPATH@/components/nsUrlClassifierLib.js
 @BINPATH@/components/url-classifier.xpt
+#endif
 
 ; GNOME hooks
 #ifdef MOZ_ENABLE_GNOME_COMPONENT
 @BINPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
 #endif
 
 ; ANGLE GLES-on-D3D rendering library
 #ifdef MOZ_ANGLE
--- a/browser/themes/winstripe/browser-aero.css
+++ b/browser/themes/winstripe/browser-aero.css
@@ -160,16 +160,27 @@
 
   #toolbar-menubar :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
   #TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
   #navigator-toolbox[tabsontop=false] > #nav-bar :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
   #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme) {
     list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
   }
 
+  #toolbar-menubar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
+  #toolbar-menubar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme),
+  #TabsToolbar[tabsontop=true] .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
+  #TabsToolbar[tabsontop=true] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme),
+  #navigator-toolbox[tabsontop=false] > #nav-bar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
+  #navigator-toolbox[tabsontop=false] > #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme),
+  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
+  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme) {
+    list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
+  }
+
   /* Vertical toolbar border */
   #main-window[sizemode=normal] #navigator-toolbox::after,
   #main-window[sizemode=normal] #navigator-toolbox[tabsontop=true] > toolbar:not(#toolbar-menubar):not(#TabsToolbar),
   #main-window[sizemode=normal] #navigator-toolbox[tabsontop=false] > toolbar:not(#toolbar-menubar):not(#nav-bar) {
     border-left: 1px solid @toolbarShadowColor@;
     border-right: 1px solid @toolbarShadowColor@;
     background-clip: padding-box;
   }
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -657,164 +657,169 @@ menuitem.bookmark-item {
 .toolbarbutton-1 {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
 
 .toolbarbutton-1:-moz-lwtheme-brighttext {
   list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
 }
 
-.toolbarbutton-1:not([type="menu-button"]) {
+.toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
+.toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
+.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker,
+.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  opacity: .4;
+}
+
+.toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
+.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+  list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow.png");
+}
+
+.toolbarbutton-1 > .toolbarbutton-menu-dropmarker:-moz-lwtheme-brighttext,
+.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme-brighttext {
+  list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
+}
+
+.toolbarbutton-1 > .toolbarbutton-icon,
+.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  -moz-margin-end: 0;
+}
+
+toolbar[mode=full] .toolbarbutton-1:not([type=menu-button]) {
   -moz-box-orient: vertical;
 }
 
-.toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon {
-  opacity: .4;
+toolbar[mode=full] .toolbarbutton-1,
+toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
+  min-width: 57px;
 }
 
 #nav-bar {
   /* force iconsize="small" on this toolbar */
   counter-reset: smallicons;
 }
 
-@navbarLargeIcons@ {
-  -moz-padding-start: 0;
-  -moz-padding-end: 2px;
-}
-
-@navbarLargeIcons@ :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon {
-  list-style-image: url("chrome://browser/skin/Toolbar.png") !important;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button,
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
-@navbarLargeIcons@ .toolbarbutton-1 {
+@navbarLargeIcons@ .toolbarbutton-1,
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-appearance: none;
-  padding: 1px 5px;
-  background: hsla(210,48%,90%,.1)
-              -moz-linear-gradient(rgba(255,255,255,.8), rgba(255,255,255,.45) 49%,
-                                   rgba(255,255,255,.35) 51%, rgba(255,255,255,.1))
-              padding-box;
-  border-radius: 2.5px;
-  border: 1px solid;
-  border-color: hsla(210,54%,20%,.13) hsla(210,54%,20%,.16) hsla(210,54%,20%,.2);
-  box-shadow: 0 1px 0 rgba(255,255,255,.3) inset,
-              0 0 0 1px rgba(255,255,255,.3) inset,
-              0 1px 0 hsla(210,54%,20%,.02),
-              /* allows winstripe-keyhole-forward-mask to be used for non-hover as well as hover: */
-              0 0 2px hsla(210,54%,20%,0);
-  color: black;
-  text-shadow: 0 0 2px white;
-  -moz-transition-property: background-color, border-color, box-shadow;
-  -moz-transition-duration: 250ms;
+  border: none;
+  padding: 0;
+  background: none;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1:not([type=menu-button]),
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button,
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+  padding: 5px 2px;
+  -moz-box-pack: center;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button) {
+  padding-left: 5px;
+  padding-right: 5px;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > menupopup {
+  margin-top: -3px;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button {
+  -moz-padding-end: 0;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  padding-left: 3px;
-  padding-right: 3px;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1[type="menu-button"] {
-  -moz-appearance: none;
-  padding: 0;
-  background: none !important;
-  border: none !important;
-  box-shadow: none !important;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 {
-  margin: 1px 3px;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(ltr),
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(rtl),
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(ltr) {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow.png");
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  -moz-border-start: none;
-  padding-left: 2px;
-  padding-right: 2px;
+  -moz-padding-start: 0;
+  -moz-box-align: center;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  padding: 2px 6px;
+  background: hsla(210,48%,90%,0) padding-box;
+  border-radius: 2.5px;
+  border: 1px solid;
+  border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0);
+  box-shadow: 0 1px 0 rgba(255,255,255,0) inset,
+              0 0 0 1px rgba(255,255,255,0) inset,
+              0 1px 0 hsla(210,54%,20%,0);
+  -moz-transition-property: background-color, border-color, box-shadow;
+  -moz-transition-duration: 150ms;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  padding: 3px 7px;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button) > .toolbarbutton-icon {
+  -moz-padding-end: 17px;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
-  margin-top: 0;
-  -moz-margin-start: 2px;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1[disabled="true"] {
-  opacity: .4;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon {
-  opacity: 1;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled="true"]):not(:active):hover,
-@navbarLargeIcons@ .toolbarbutton-1:not([open="true"]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled="true"]),
-@navbarLargeIcons@ .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):not([checked="true"]):not([open="true"]):not(:active):hover {
+  -moz-margin-start: -15px;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  -moz-border-end: none;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  -moz-border-start-color: rgba(0,0,0,0.1);
+  padding: 8px 2px 7px;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl),
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):not(:active):hover > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1:not([open=true]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
+@navbarLargeIcons@ .toolbarbutton-1:not([type=menu-button]):not([disabled=true]):not([checked=true]):not([open=true]):not(:active):hover > .toolbarbutton-icon {
+  background-image: -moz-linear-gradient(rgba(255,255,255,.8), rgba(255,255,255,.45) 49%,
+                                         rgba(255,255,255,.35) 51%, rgba(255,255,255,.1));
   background-color: hsla(210,48%,96%,.75);
   border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
   box-shadow: 0 1px 0 rgba(255,255,255,.3) inset,
               0 0 0 1px rgba(255,255,255,.3) inset,
               0 1px 0 hsla(210,54%,20%,.03),
               0 0 2px hsla(210,54%,20%,.1);
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled="true"]):hover:active,
-@navbarLargeIcons@ .toolbarbutton-1:hover:active > .toolbarbutton-menubutton-dropmarker:not([disabled="true"]),
-@navbarLargeIcons@ .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker,
-@navbarLargeIcons@ .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):hover:active,
-@navbarLargeIcons@ .toolbarbutton-1:not([type="menu-button"])[checked="true"],
-@navbarLargeIcons@ .toolbarbutton-1[open="true"] {
+@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1:hover:active > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
+@navbarLargeIcons@ .toolbarbutton-1[open=true] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
+@navbarLargeIcons@ .toolbarbutton-1:not([type=menu-button]):not([disabled=true]):hover:active > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1:not([type=menu-button])[checked=true] > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1[open=true] > .toolbarbutton-icon {
   background-color: hsla(210,54%,20%,.2);
   border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
   box-shadow: 0 1px 1px rgba(0,0,0,.1) inset,
               0 0 2px rgba(0,0,0,.3) inset,
               /* allows winstripe-keyhole-forward-mask to be used for non-hover as well as hover: */
               0 1px 0 hsla(210,54%,20%,0),
               0 0 2px hsla(210,54%,20%,0);
   text-shadow: none;
   -moz-transition: none;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1[checked="true"]:not(:active):hover {
+@navbarLargeIcons@ .toolbarbutton-1[checked=true]:not(:active):hover > .toolbarbutton-icon {
   background-color: rgba(90%,90%,90%,.4);
   -moz-transition: background-color .4s;
 }
 
-.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-.toolbarbutton-1 > .toolbarbutton-icon {
-  -moz-margin-end: 0;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon {
-  margin: 1px;
-}
-
-toolbar[mode="full"] .toolbarbutton-1,
-toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-  min-width: 57px;
-}
-
 :-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1,
 :-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-appearance: none;
   border-style: none;
   padding: 0 3px;
 }
@@ -854,118 +859,111 @@ toolbar[mode="full"] .toolbarbutton-1 > 
 }
 
 #back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #forward-button:-moz-locale-dir(rtl),
 #forward-button:-moz-locale-dir(rtl) > .toolbarbutton-text {
   -moz-transform: scaleX(-1);
 }
 
-@navbarLargeIcons@ #forward-button {
-  border-left-style: none;
-  -moz-margin-start: 0 !important;
+@conditionalForwardWithUrlbar@ {
+  -moz-box-align: center;
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-  -moz-margin-end: 0;
+  padding: 0;
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button > menupopup {
+  margin-top: 1px;
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button > .toolbarbutton-icon {
+  /*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
+  mask: url(chrome://browser/content/browser.xul#winstripe-keyhole-forward-mask);
+  -moz-margin-start: -6px !important;
+  border-left-style: none;
+  border-radius: 0;
+  padding-left: 7px;
+  padding-right: 3px;
+}
+
+@conditionalForwardWithUrlbar@ > :-moz-any(#forward-button:not(:hover):not(:active):not([open]),
+                                           #forward-button[disabled]) > .toolbarbutton-icon {
+  background-color: hsla(210,48%,90%,.1);
+  background-image: -moz-linear-gradient(rgba(255,255,255,.8), rgba(255,255,255,.45) 49%,
+                                         rgba(255,255,255,.35) 51%, rgba(255,255,255,.1));
+  border-color: hsla(210,54%,20%,.13) hsla(210,54%,20%,.16) hsla(210,54%,20%,.2);
+  box-shadow: 0 1px 0 rgba(255,255,255,.3) inset,
+              0 0 0 1px rgba(255,255,255,.3) inset,
+              0 1px 0 hsla(210,54%,20%,.02),
+              /* allows winstripe-keyhole-forward-mask to be used for non-hover as well as hover: */
+              0 0 2px hsla(210,54%,20%,0);
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
   -moz-transition: opacity @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
   opacity: 0;
 }
 
-@navbarLargeIcons@ #back-button:-moz-locale-dir(ltr) {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-
-@navbarLargeIcons@ #back-button:-moz-locale-dir(rtl),
-@navbarLargeIcons@ #forward-button {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-@navbarLargeIcons@ #back-button {
+@conditionalForwardWithUrlbar@ > #back-button {
   -moz-image-region: rect(18px, 20px, 38px, 0);
-  -moz-margin-end: 0 !important;
-  margin: -5px 0;
-  padding-top: 0;
-  padding-bottom: 0;
+  padding-top: 3px;
+  padding-bottom: 3px;
   -moz-padding-start: 5px;
   -moz-padding-end: 0;
   position: relative;
   z-index: 1;
   border-radius: 0 10000px 10000px 0;
-  background: transparent;
-  border: none;
-  box-shadow: none;
-}
-
-@navbarLargeIcons@ #back-button:-moz-locale-dir(rtl) {
+}
+
+@conditionalForwardWithUrlbar@ > #back-button:-moz-locale-dir(rtl) {
   border-radius: 10000px 0 0 10000px;
 }
 
-@navbarLargeIcons@ #back-button > .toolbarbutton-icon {
+@conditionalForwardWithUrlbar@ > #back-button > menupopup {
+  margin-top: -1px;
+}
+
+@conditionalForwardWithUrlbar@ > #back-button > .toolbarbutton-icon {
   border-radius: 10000px;
   padding: 5px;
   border: none;
   background: hsla(210,48%,90%,.1)
               -moz-linear-gradient(rgba(255,255,255,.88), rgba(255,255,255,.45) 49%,
                                    rgba(255,255,255,.35) 51%, rgba(255,255,255,.67));
   box-shadow: 0 1px 0 rgba(255,255,255,.3) inset,
               0 0 0 1px rgba(255,255,255,.3) inset,
               0 1px 0 hsla(210,54%,20%,.02),
               0 0 0 1px rgba(0,0,0,.15);
   -moz-transition-property: background-color, box-shadow;
   -moz-transition-duration: 250ms;
 }
 
-@navbarLargeIcons@ #back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
+@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
   background-color: hsla(210,48%,96%,.75);
   box-shadow: 0 1px 0 rgba(255,255,255,.3) inset,
               0 0 0 1px rgba(255,255,255,.1) inset,
               0 1px 0 hsla(210,54%,20%,.03),
               0 0 0 1px rgba(0,0,0,.2),
               0 0 2px 1px hsla(210,54%,20%,.2);
 }
 
-@navbarLargeIcons@ #back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
-@navbarLargeIcons@ #back-button[open="true"] > .toolbarbutton-icon {
+@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
+@conditionalForwardWithUrlbar@ > #back-button[open="true"] > .toolbarbutton-icon {
   background-color: hsla(210,54%,20%,.2);
   box-shadow: 0 1px 1px rgba(0,0,0,.1) inset,
               0 0 2px rgba(0,0,0,.3) inset,
               0 0 0 1px rgba(0,0,0,.2);
   -moz-transition: none;
 }
 
-@navbarLargeIcons@[currentset*="unified-back-forward-button"],
-@navbarLargeIcons@:not([currentset]) {
-  padding-top: 3px;
-  padding-bottom: 5px;
-}
-
-#navigator-toolbox[iconsize="large"][mode="icons"][tabsontop="true"] > #nav-bar[currentset*="unified-back-forward-button"],
-#navigator-toolbox[iconsize="large"][mode="icons"][tabsontop="true"] > #nav-bar:not([currentset]) {
-  padding-top: 5px;
-}
-
-@navbarLargeIcons@ #forward-button {
-  /*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
-  mask: url(chrome://browser/content/browser.xul#winstripe-keyhole-forward-mask);
-  -moz-margin-start: -6px !important;
-  padding-left: 7px;
-  padding-right: 3px;
-}
-
 .unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr),
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("chrome://browser/skin/menu-back.png") !important;
 }
 
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
 .unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
@@ -1072,20 +1070,16 @@ toolbar[mode="full"] .toolbarbutton-1 > 
 #bookmarks-menu-button.bookmark-item {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
 
 #bookmarks-menu-button.bookmark-item:-moz-lwtheme-brighttext {
   list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
 }
 
-#bookmarks-menu-button.toolbarbutton-1 {
-  -moz-box-orient: horizontal;
-}
-
 /* print button */
 
 #print-button {
   -moz-image-region: rect(0, 162px, 18px, 144px);
 }
 
 /* toolbar new tab button */
 
@@ -1128,37 +1122,16 @@ toolbar[mode="full"] .toolbarbutton-1 > 
 #zoom-out-button {
   -moz-image-region: rect(0, 288px, 18px, 270px);
 }
 
 #zoom-in-button {
   -moz-image-region: rect(0, 306px, 18px, 288px);
 }
 
-#nav-bar #zoom-out-button {
-  -moz-margin-end: 0;
-}
-
-#nav-bar #zoom-in-button {
-  -moz-border-start: none;
-  -moz-margin-start: 0;
-}
-
-#nav-bar #zoom-out-button:-moz-locale-dir(ltr),
-#nav-bar #zoom-in-button:-moz-locale-dir(rtl) {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-
-#nav-bar #zoom-out-button:-moz-locale-dir(rtl),
-#nav-bar #zoom-in-button:-moz-locale-dir(ltr) {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
 /* sync button */
 
 #sync-button {
   -moz-image-region: rect(0, 324px, 18px, 306px);
 }
 
 #sync-button[status="active"] {
   list-style-image: url("chrome://browser/skin/sync-throbber.png");
--- a/build/mobile/droid.py
+++ b/build/mobile/droid.py
@@ -52,17 +52,20 @@ class DroidMixin(object):
     returns:
     success: True
     failure: False
     """
     # only one instance of an application may be running at once
     if self.processExist(app):
       return False
 
-    acmd = [ "am", "start", "-a", intent, "-W", "-n", "%s/.%s" % (app, activity)]
+    acmd = [ "am", "start", "-W", "-n", "%s/.%s" % (app, activity)]
+
+    if intent:
+      acmd.extend(["-a", intent])
 
     if extra_args:
       acmd.extend(["--es", "args", " ".join(extra_args)])
 
     if env:
       envCnt = 0
       # env is expected to be a dict of environment variables
       for envkey, envval in env.iteritems():
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -61,17 +61,16 @@ nsIMutationObserver2.h \
 nsINameSpaceManager.h \
 nsINode.h \
 nsINodeInfo.h \
 nsINodeList.h \
 nsIScriptElement.h \
 nsIStyleSheetLinkingElement.h \
 nsIContentSerializer.h \
 nsIXPathEvaluatorInternal.h \
-mozISanitizingSerializer.h \
 nsCaseTreatment.h \
 nsContentCID.h \
 nsCopySupport.h \
 nsContentCreatorFunctions.h \
 nsDOMFile.h \
 nsLineBreaker.h \
 nsReferencedElement.h \
 nsTreeSanitizer.h \
deleted file mode 100644
--- a/content/base/public/mozISanitizingSerializer.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- Mode: C++; 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.org HTML Sanitizer code.
- *
- * The Initial Developer of the Original Code is
- * Ben Bucksch <mozilla@bucksch.org>.
- * Portions created by the Initial Developer are Copyright (C) 2002
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Netscape
- *
- * 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 ***** */
-
-/* Cleans up HTML source from unwanted tags/attributes
-
-   This class implements a content sink, which takes a parsed HTML document
-   and removes all tags and attributes that are not explicitly allowed.
-
-   This may improve the viewing experience of the user and/or the
-   security/privacy.
-
-   What is allowed is defined by a string (format described before the
-   implementation of |mozHTMLSanitizer::ParsePrefs()|). The sytnax of the
-   definition is not very rich - you can only (dis)allow certain tags and
-   attributes, but not where they may appear. (This makes the implementation
-   much more simple.) E.g. it is impossible to disallow ordinary text as a
-   direct child of the <head> node or to disallow multiple <head> nodes.
-
-   We also remove some known bad attribute values like javascript: URLs.
-   Draconian attitude.
-
-   Currently, the output of this class is unparsed (!) HTML source, which
-   means that each document has to go through the parser twice. Of course,
-   that is a performance killer. There are some reasons for for me doing it
-   that way:
-   * There is, to my knowledge, no interface to hook up such modifiers
-     in the document display data flow. We have a nice interface for doing
-     the modifications (the DOM), but no place to get the DOM and to invoke
-     this code. As I don't want to hack this directly into the html sink,
-     I'd have to create a generic interface first, which is too much work for
-     me at the moment.
-   * It is quite easy to hook up modifiers for the (unparsed) data stream,
-     both in netwerk (for the browser) and esp. in libmime (for Mailnews).
-   * It seems like the safest method - it is easier to debug (you have the
-     HTML source output to check) and is less prone to security-relevant bugs
-     and regressions, because in the case of a bug, it will probably fall back
-     to not outputting, which is safer than erring on the side of letting
-     something slip through (most of the alternative approaches listed below
-     are probably vulnerable to the latter).
-   * It should be possible to later change this class to output a parsed HTML
-     document.
-   So, in other words, I had the choice between better design and better
-   performance. I choose design. Bad performance has an effect on the users
-   of this class only, while bad design has an effect on all users and 
-   programmers.
-
-   That being said, I have some ideas, how do make it much more efficient, but
-   they involve hacking core code.
-   * At some point when we have DOM, but didn't do anything with it yet
-     (in particular, didn't load any external objects or ran any javascript),
-     walk the DOM and delete everything the user doesn't explicitly like.
-   * There's this nice GetPref() in the HTMLContentSink. It isn't used exactly
-     as I would like to, but that should be doable. Bascially, before
-     processing any tag (e.g. in OpenContainer or AddLeaf), ask that
-     function, if the tag is allowed. If not, just return.
-   In any case, there's the problem, how the users of the renderer
-   (e.g. Mailnews) can tell it to use the sanitizer and which tags are
-   allowed (the browser may want to allow more tags than Mailnews).
-   That probably means that I have to hack into the docshell (incl. its
-   interface) or similar, which I would really like to avoid.
-   Any ideas appreciated.
-*/
-#ifndef _mozISanitizingSerializer_h__
-#define _mozISanitizingSerializer_h__
-
-#include "nsISupports.h"
-
-class nsAString;
-
-#define MOZ_SANITIZINGHTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/htmlsanitizer;1"
-
-/* starting interface:    nsIContentSerializer */
-#define MOZ_ISANITIZINGHTMLSERIALIZER_IID_STR "feca3c34-205e-4ae5-bd1c-03c686ff012b"
-
-#define MOZ_ISANITIZINGHTMLSERIALIZER_IID \
-  {0xfeca3c34, 0x205e, 0x4ae5, \
-    { 0xbd, 0x1c, 0x03, 0xc6, 0x86, 0xff, 0x01, 0x2b }}
-
-class mozISanitizingHTMLSerializer : public nsISupports {
- public: 
-
-  NS_DECLARE_STATIC_IID_ACCESSOR(MOZ_ISANITIZINGHTMLSERIALIZER_IID)
-
-  NS_IMETHOD Initialize(nsAString* aOutString,
-                        PRUint32 aFlags,
-                        const nsAString& allowedTags) = 0;
-  // This function violates string ownership rules, see impl.
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(mozISanitizingHTMLSerializer,
-                              MOZ_ISANITIZINGHTMLSERIALIZER_IID)
-
-#endif
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1510,16 +1510,23 @@ public:
    * Initialize and set the dataTransfer field of an nsDragEvent.
    */
   static nsresult SetDataTransferInEvent(nsDragEvent* aDragEvent);
 
   // filters the drag and drop action to fit within the effects allowed and
   // returns it.
   static PRUint32 FilterDropEffect(PRUint32 aAction, PRUint32 aEffectAllowed);
 
+  /*
+   * Return true if the target of a drop event is a content document that is
+   * an ancestor of the document for the source of the drag.
+   */
+  static bool CheckForSubFrameDrop(nsIDragSession* aDragSession,
+                                   nsDragEvent* aDropEvent);
+
   /**
    * Return true if aURI is a local file URI (i.e. file://).
    */
   static bool URIIsLocalFile(nsIURI *aURI);
 
   /**
    * Given a URI, return set beforeHash to the part before the '#', and
    * afterHash to the remainder of the URI, including the '#'.
@@ -1654,25 +1661,29 @@ public:
   {
     const char* s = aStr2;
     return EqualsLiteralIgnoreASCIICase(aStr1, s, N-1);
   }
 #endif
 
   /**
    * Convert ASCII A-Z to a-z.
+   * @return NS_OK on success, or NS_ERROR_OUT_OF_MEMORY if making the string
+   * writable needs to allocate memory and that allocation fails.
    */
-  static void ASCIIToLower(nsAString& aStr);
-  static void ASCIIToLower(const nsAString& aSource, nsAString& aDest);
+  static nsresult ASCIIToLower(nsAString& aStr);
+  static nsresult ASCIIToLower(const nsAString& aSource, nsAString& aDest);
 
   /**
    * Convert ASCII a-z to A-Z.
+   * @return NS_OK on success, or NS_ERROR_OUT_OF_MEMORY if making the string
+   * writable needs to allocate memory and that allocation fails.
    */
-  static void ASCIIToUpper(nsAString& aStr);
-  static void ASCIIToUpper(const nsAString& aSource, nsAString& aDest);
+  static nsresult ASCIIToUpper(nsAString& aStr);
+  static nsresult ASCIIToUpper(const nsAString& aSource, nsAString& aDest);
 
   // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
   static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
   static nsIInterfaceRequestor* GetSameOriginChecker();
 
   static nsIThreadJSContextStack* ThreadJSContextStack()
   {
     return sThreadJSContextStack;
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -72,17 +72,16 @@ EXPORTS_NAMESPACES = mozilla/dom
 
 EXPORTS_mozilla/dom = \
   Link.h \
   $(NULL)
 
 LOCAL_INCLUDES = -I$(srcdir)/js/xpconnect/src
 
 CPPSRCS		= \
-		mozSanitizingSerializer.cpp \
 		nsAtomListUtils.cpp \
 		nsAttrAndChildArray.cpp \
 		nsAttrValue.cpp \
 		nsAttrValueOrString.cpp \
 		nsCCUncollectableMarker.cpp \
 		nsChannelPolicy.cpp \
 		nsCommentNode.cpp \
 		nsContentAreaDragDrop.cpp \
deleted file mode 100644
--- a/content/base/src/mozSanitizingSerializer.cpp
+++ /dev/null
@@ -1,684 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 sw=2 et tw=80: */
-/* ***** 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.org HTML Sanitizer code.
- *
- * The Initial Developer of the Original Code is
- * Ben Bucksch <mozilla@bucksch.org>.
- * Portions created by the Initial Developer are Copyright (C) 2002
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Netscape
- *
- * 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 ***** */
-
-/*
- * A serializer and content sink that removes potentially insecure or
- * otherwise dangerous or offending HTML (eg for display of HTML
- * e-mail attachments or something).
- */
-
-/* I used nsPlaintextSerializer as base for this class. I don't understand
-   all of the functions in the beginning. Possible that I fail to do
-   something or do something useless.
-   I am not proud about the implementation here at all.
-   Feel free to fix it :-).
-*/
-
-#include "mozSanitizingSerializer.h"
-#include "nsIServiceManager.h"
-#include "nsIDOMElement.h"
-#include "nsTextFragment.h"
-#include "nsContentUtils.h"
-#include "nsReadableUtils.h"
-#include "plstr.h"
-#include "nsIProperties.h"
-#include "nsUnicharUtils.h"
-#include "nsIURI.h"
-#include "nsNetUtil.h"
-#include "nsEscape.h"
-#include "mozilla/dom/Element.h"
-
-using namespace mozilla::dom;
-
-static inline PRUnichar* escape(const nsString& source)
-{
-  return nsEscapeHTML2(source.get(), source.Length()); 
-}
-
-/* XXX: |printf|s in some error conditions. They are intended as information
-   for the user, because they complain about malformed pref values.
-   Not sure, if popping up dialog boxes is the right thing for such code
-   (and if so, how to do it).
- */
-
-#define TEXT_REMOVED "&lt;Text removed&gt;"
-#define TEXT_BREAKER "|"
-
-nsresult NS_NewSanitizingHTMLSerializer(nsIContentSerializer** aSerializer)
-{
-  mozSanitizingHTMLSerializer* it = new mozSanitizingHTMLSerializer();
-  NS_ADDREF(it);
-  *aSerializer = it;
-  return NS_OK;
-}
-
-mozSanitizingHTMLSerializer::mozSanitizingHTMLSerializer()
-  : mSkipLevel(0),
-    mAllowedTags(30) // Just some initial buffer size
-{
-  mOutputString = nsnull;
-}
-
-mozSanitizingHTMLSerializer::~mozSanitizingHTMLSerializer()
-{
-#ifdef DEBUG_BenB
-  printf("Output:\n%s\n", NS_LossyConvertUTF16toASCII(*mOutputString).get());
-#endif
-  mAllowedTags.Enumerate(ReleaseProperties);
-}
-
-//<copy from="xpcom/ds/nsProperties.cpp">
-bool
-mozSanitizingHTMLSerializer::ReleaseProperties(nsHashKey* key, void* data,
-                                               void* closure)
-{
-  nsIProperties* prop = (nsIProperties*)data;
-  NS_IF_RELEASE(prop);
-  return true;
-}
-//</copy>
-
-NS_IMPL_ISUPPORTS4(mozSanitizingHTMLSerializer,
-                   nsIContentSerializer,
-                   nsIContentSink,
-                   nsIHTMLContentSink,
-                   mozISanitizingHTMLSerializer)
-
-
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::Init(PRUint32 aFlags, PRUint32 dummy,
-                                  const char* aCharSet, bool aIsCopying,
-                                  bool aIsWholeDocument)
-{
-  NS_ENSURE_TRUE(nsContentUtils::GetParserService(), NS_ERROR_UNEXPECTED);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozSanitizingHTMLSerializer::Initialize(nsAString* aOutString,
-                                        PRUint32 aFlags,
-                                        const nsAString& allowedTags)
-{
-  nsresult rv = Init(aFlags, 0, nsnull, false, false);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // XXX This is wrong. It violates XPCOM string ownership rules.
-  // We're only getting away with this because instances of this
-  // class are restricted to single function scope.
-  // (Comment copied from nsPlaintextSerializer)
-  mOutputString = aOutString;
-
-  ParsePrefs(allowedTags);
-
-  return NS_OK;
-}
-
-// This is not used within the class, but maybe called from somewhere else?
-NS_IMETHODIMP
-mozSanitizingHTMLSerializer::Flush(nsAString& aStr)
-{
-#ifdef DEBUG_BenB
-  printf("Flush: -%s-", NS_LossyConvertUTF16toASCII(aStr).get());
-#endif
-  Write(aStr);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-mozSanitizingHTMLSerializer::AppendDocumentStart(nsIDocument *aDocument,
-                                                 nsAString& aStr)
-{
-  return NS_OK;
-}
-
-void
-mozSanitizingHTMLSerializer::Write(const nsAString& aString)
-{
-  mOutputString->Append(aString);
-}
-
-
-NS_IMETHODIMP
-mozSanitizingHTMLSerializer::IsEnabled(PRInt32 aTag, bool* aReturn)
-{
-  *aReturn = false;
-  return NS_OK;
-}
-
-
-/**
- * Returns true, if the id represents a container
- */
-bool
-mozSanitizingHTMLSerializer::IsContainer(PRInt32 aId)
-{
-  bool isContainer = false;
-
-  nsIParserService* parserService = nsContentUtils::GetParserService();
-  if (parserService) {
-    parserService->IsContainer(aId, isContainer);
-  }
-
-  return isContainer;
-}
-
-
-/* XXX I don't really know, what these functions do, but they seem to be
-   needed ;-). Mostly copied from nsPlaintextSerializer. */
-/* akk says:
-   "I wonder if the sanitizing class could inherit from nsHTMLSerializer,
-   so that at least these methods that none of us understand only have to be
-   written once?" */
-
-// static
-PRInt32
-mozSanitizingHTMLSerializer::GetIdForContent(nsIContent* aContent)
-{
-  if (!aContent->IsHTML()) {
-    return eHTMLTag_unknown;
-  }
-
-  nsIParserService* parserService = nsContentUtils::GetParserService();
-
-  return parserService ? parserService->HTMLAtomTagToId(aContent->Tag()) :
-                         eHTMLTag_unknown;
-}
-
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::AppendText(nsIContent* aText,
-                                        PRInt32 aStartOffset,
-                                        PRInt32 aEndOffset, 
-                                        nsAString& aStr)
-{
-  nsresult rv = NS_OK;
-
-  mOutputString = &aStr;
-
-  nsAutoString linebuffer;
-  rv = DoAddLeaf(eHTMLTag_text, linebuffer);
-
-  return rv;
-}
-
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::AppendElementStart(Element* aElement,
-                                                Element* aOriginalElement,
-                                                nsAString& aStr)
-{
-  NS_ENSURE_ARG(aElement);
-
-  mElement = aElement;
-
-  mOutputString = &aStr;
-
-  PRInt32 id = GetIdForContent(mElement);
-
-  bool isContainer = IsContainer(id);
-
-  nsresult rv;
-  if (isContainer) {
-    rv = DoOpenContainer(id);
-  }
-  else {
-    rv = DoAddLeaf(id, EmptyString());
-  }
-
-  mElement = nsnull;
-  mOutputString = nsnull;
-
-  return rv;
-} 
- 
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::AppendElementEnd(Element* aElement,
-                                              nsAString& aStr)
-{
-  NS_ENSURE_ARG(aElement);
-
-  mElement = aElement;
-
-  mOutputString = &aStr;
-
-  PRInt32 id = GetIdForContent(mElement);
-
-  bool isContainer = IsContainer(id);
-
-  nsresult rv = NS_OK;
-  if (isContainer) {
-    rv = DoCloseContainer(id);
-  }
-
-  mElement = nsnull;
-  mOutputString = nsnull;
-
-  return rv;
-}
-
-NS_IMETHODIMP
-mozSanitizingHTMLSerializer::OpenContainer(const nsIParserNode& aNode)
-{
-  PRInt32 type = aNode.GetNodeType();
-
-  mParserNode = const_cast<nsIParserNode *>(&aNode);
-  return DoOpenContainer(type);
-}
-
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::CloseContainer(const nsHTMLTag aTag)
-{
-  return DoCloseContainer(aTag);
-}
-
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::AddLeaf(const nsIParserNode& aNode)
-{
-  eHTMLTags type = (eHTMLTags)aNode.GetNodeType();
-  const nsAString& text = aNode.GetText();
-
-  mParserNode = const_cast<nsIParserNode*>(&aNode);
-  return DoAddLeaf(type, text);
-}
-
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::SetDocumentCharset(nsACString& aCharset)
-{
-  // No idea, if this works - it isn't invoked by |TestOutput|.
-  Write(NS_LITERAL_STRING("\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=")
-        /* Danger: breaking the line within the string literal, like
-           "foo"\n"bar", breaks win32! */
-        + nsAdoptingString(escape(NS_ConvertASCIItoUTF16(aCharset)))
-        + NS_LITERAL_STRING("\">\n"));
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-mozSanitizingHTMLSerializer::OpenHead()
-{
-  // XXX We don't have a parser node here, is it okay to ignore this?
-  // return OpenContainer(aNode);
-  return NS_OK;
-}
-
-// Here comes the actual code...
-
-nsresult
-mozSanitizingHTMLSerializer::DoOpenContainer(PRInt32 aTag)
-{
-  eHTMLTags type = (eHTMLTags)aTag;
-
-  if (mSkipLevel == 0 && IsAllowedTag(type))
-  {
-    nsIParserService* parserService = nsContentUtils::GetParserService();
-    if (!parserService)
-      return NS_ERROR_OUT_OF_MEMORY;
-    const PRUnichar* tag_name = parserService->HTMLIdToStringTag(aTag);
-    NS_ENSURE_TRUE(tag_name, NS_ERROR_INVALID_POINTER);
-
-    Write(NS_LITERAL_STRING("<") + nsDependentString(tag_name));
-
-    // Attributes
-    if (mParserNode)
-    {
-      PRInt32 count = mParserNode->GetAttributeCount();
-      for (PRInt32 i = 0; i < count; i++)
-      {
-        const nsAString& key = mParserNode->GetKeyAt(i);
-        if(IsAllowedAttribute(type, key))
-        {
-          // Ensure basic sanity of value
-          nsAutoString value(mParserNode->GetValueAt(i));
-                    // SanitizeAttrValue() modifies |value|
-          if (NS_SUCCEEDED(SanitizeAttrValue(type, key, value)))
-          {
-            // Write out
-            Write(NS_LITERAL_STRING(" "));
-            Write(key); // I get an infinive loop with | + key + | !!!
-            Write(NS_LITERAL_STRING("=\"") + value + NS_LITERAL_STRING("\""));
-          }
-        }
-      }
-    }
-
-    Write(NS_LITERAL_STRING(">"));
-  }
-  else if (mSkipLevel != 0 || type == eHTMLTag_script || type == eHTMLTag_style)
-    ++mSkipLevel;
-  else
-    Write(NS_LITERAL_STRING(" "));
-
-  return NS_OK;
-
-}
-
-nsresult
-mozSanitizingHTMLSerializer::DoCloseContainer(PRInt32 aTag)
-{
-  eHTMLTags type = (eHTMLTags)aTag;
-
-  if (mSkipLevel == 0 && IsAllowedTag(type)) {
-    nsIParserService* parserService = nsContentUtils::GetParserService();
-    if (!parserService)
-      return NS_ERROR_OUT_OF_MEMORY;
-    const PRUnichar* tag_name = parserService->HTMLIdToStringTag(aTag);
-    NS_ENSURE_TRUE(tag_name, NS_ERROR_INVALID_POINTER);
-
-    Write(NS_LITERAL_STRING("</") + nsDependentString(tag_name)
-          + NS_LITERAL_STRING(">"));
-  }
-  else if (mSkipLevel == 0)
-    Write(NS_LITERAL_STRING(" "));
-  else
-    --mSkipLevel;
-
-  return NS_OK;
-}
-
-nsresult
-mozSanitizingHTMLSerializer::DoAddLeaf(PRInt32 aTag,
-                                       const nsAString& aText)
-{
-  if (mSkipLevel != 0)
-    return NS_OK;
-
-  eHTMLTags type = (eHTMLTags)aTag;
-
-  nsresult rv = NS_OK;
-
-  if (type == eHTMLTag_whitespace ||
-      type == eHTMLTag_newline)
-  {
-    Write(aText); // sure to be safe?
-  }
-  else if (type == eHTMLTag_text)
-  {
-    nsAutoString text(aText);
-    if(NS_SUCCEEDED(SanitizeTextNode(text)))
-      Write(text);
-    else
-      Write(NS_LITERAL_STRING(TEXT_REMOVED)); // Does not happen (yet)
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else if (type == eHTMLTag_entity)
-  {
-    Write(NS_LITERAL_STRING("&"));
-    Write(aText); // sure to be safe?
-    // using + operator here might give an infinitive loop, see above.
-    // not adding ";", because Gecko delivers that as part of |aText| (freaky)
-  }
-  else
-  {
-    DoOpenContainer(type);
-  }
-
-  return rv;
-}
-
-
-/**
-   Similar to SanitizeAttrValue.
- */
-nsresult
-mozSanitizingHTMLSerializer::SanitizeTextNode(nsString& aText /*inout*/)
-{
-  aText.Adopt(escape(aText));
-  return NS_OK;
-}
-
-/**
-   Ensures basic sanity of attribute value.
-   This function also (tries to :-( ) makes sure, that no
-   unwanted / dangerous URLs appear in the document
-   (like javascript: and data:).
-
-   Pass the value as |aValue| arg. It will be modified in-place.
-
-   If the value is not allowed at all, we return with NS_ERROR_ILLEGAL_VALUE.
-   In that case, do not use the |aValue|, but output nothing.
- */
-nsresult
-mozSanitizingHTMLSerializer::SanitizeAttrValue(nsHTMLTag aTag,
-                                               const nsAString& anAttrName,
-                                               nsString& aValue /*inout*/)
-{
-  /* First, cut the attribute to 1000 chars.
-     Attributes with values longer than 1000 chars seem bogus,
-     considering that we don't support any JS. The longest attributes
-     I can think of are URLs, and URLs with 1000 chars are likely to be
-     bogus, too. */
-  aValue = Substring(aValue, 0, 1000);
-  //aValue.Truncate(1000); //-- this cuts half of the document !!?!!
-
-  aValue.Adopt(escape(aValue));
-
-  /* Check some known bad stuff. Add more!
-     I don't care too much, if it happens to trigger in some innocent cases
-     (like <img alt="Statistical data: Mortage rates and newspapers">) -
-     security first. */
-  if (aValue.Find("javascript:") != kNotFound ||
-      aValue.Find("data:") != kNotFound ||
-      aValue.Find("base64") != kNotFound)
-    return NS_ERROR_ILLEGAL_VALUE;
-
-  // Check img src scheme
-  if (aTag == eHTMLTag_img && 
-      anAttrName.LowerCaseEqualsLiteral("src"))
-  {
-    nsresult rv;
-    nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsCAutoString scheme;
-    rv = ioService->ExtractScheme(NS_LossyConvertUTF16toASCII(aValue), scheme);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!scheme.Equals("cid", nsCaseInsensitiveCStringComparator()))
-      return NS_ERROR_ILLEGAL_VALUE;
-  }
-
-#ifdef DEBUG_BenB
-  printf("attribute value for %s: -%s-\n",
-         NS_LossyConvertUTF16toASCII(anAttrName).get(),
-         NS_LossyConvertUTF16toASCII(aValue).get());
-#endif
-
-  return NS_OK;
-}
-
-/**
- */
-bool
-mozSanitizingHTMLSerializer::IsAllowedTag(nsHTMLTag aTag)
-{
-
-  nsPRUint32Key tag_key(aTag);
-#ifdef DEBUG_BenB
-  printf("IsAllowedTag %d: %s\n",
-         aTag,
-         mAllowedTags.Exists(&tag_key)?"yes":"no");
-#endif
-  return mAllowedTags.Exists(&tag_key);
-}
-
-
-/**
- */
-bool
-mozSanitizingHTMLSerializer::IsAllowedAttribute(nsHTMLTag aTag,
-                                             const nsAString& anAttributeName)
-{
-#ifdef DEBUG_BenB
-  printf("IsAllowedAttribute %d, -%s-\n",
-         aTag,
-         NS_LossyConvertUTF16toASCII(anAttributeName).get());
-#endif
-  nsresult rv;
-
-  nsPRUint32Key tag_key(aTag);
-  nsIProperties* attr_bag = (nsIProperties*)mAllowedTags.Get(&tag_key);
-  NS_ENSURE_TRUE(attr_bag, false);
-
-  bool allowed;
-  nsCAutoString attr;
-  ToLowerCase(NS_ConvertUTF16toUTF8(anAttributeName), attr);
-  rv = attr_bag->Has(attr.get(), &allowed);
-  if (NS_FAILED(rv))
-    return false;
-
-#ifdef DEBUG_BenB
-  printf(" Allowed: %s\n", allowed?"yes":"no");
-#endif
-  return allowed;
-}
-
-
-/**
-   aPref is a long string, which holds an exhaustive list of allowed tags
-   and attributes. All other tags and attributes will be removed.
-
-   aPref has the format
-   "html head body ul ol li a(href,name,title) img(src,alt,title) #text"
-   i.e.
-   - tags are separated by whitespace
-   - the attribute list follows the tag directly in brackets
-   - the attributes are separated by commas.
-
-   There is no way to express further restrictions, like "no text inside the
-   <head> element". This is so to considerably reduce the complexity of the
-   pref and this implementation.
-
-   Update: Akk told me that I might be able to use DTD classes. Later(TM)...
- */
-nsresult
-mozSanitizingHTMLSerializer::ParsePrefs(const nsAString& aPref)
-{
-  char* pref = ToNewCString(aPref);
-  char* tags_lasts;
-  for (char* iTag = PL_strtok_r(pref, " ", &tags_lasts);
-       iTag;
-       iTag = PL_strtok_r(NULL, " ", &tags_lasts))
-  {
-    ParseTagPref(nsCAutoString(iTag));
-  }
-  delete[] pref;
-
-  return NS_OK;
-}
-
-
-/**
-   Parses e.g. "a(href,title)" (but not several tags at once).
- */
-nsresult
-mozSanitizingHTMLSerializer::ParseTagPref(const nsCAutoString& tagpref)
-{
-  nsIParserService* parserService = nsContentUtils::GetParserService();
-  if (!parserService)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  // Parsing tag
-  PRInt32 bracket = tagpref.FindChar('(');
-  if (bracket == 0)
-  {
-    printf(" malformed pref: %s\n", tagpref.get());
-    return NS_ERROR_CANNOT_CONVERT_DATA;
-  }
-
-  nsAutoString tag;
-  CopyUTF8toUTF16(StringHead(tagpref, bracket), tag);
-
-  // Create key
-  PRInt32 tag_id = parserService->HTMLStringTagToId(tag);
-  if (tag_id == eHTMLTag_userdefined)
-  {
-    printf(" unknown tag <%s>, won't add.\n",
-           NS_ConvertUTF16toUTF8(tag).get());
-    return NS_ERROR_CANNOT_CONVERT_DATA;
-  }
-  nsPRUint32Key tag_key(tag_id);
-
-  if (mAllowedTags.Exists(&tag_key))
-  {
-    printf(" duplicate tag: %s\n", NS_ConvertUTF16toUTF8(tag).get());
-    return NS_ERROR_CANNOT_CONVERT_DATA;
-  }
-  if (bracket == kNotFound)
-    /* There are no attributes in the pref. So, allow none; only the tag
-       itself */
-  {
-    mAllowedTags.Put(&tag_key, 0);
-  }
-  else
-  {
-    // Attributes
-
-    // where is the macro for non-fatal errors in opt builds?
-    if(tagpref[tagpref.Length() - 1] != ')' ||
-       tagpref.Length() < PRUint32(bracket) + 3)
-    {
-      printf(" malformed pref: %s\n", tagpref.get());
-      return NS_ERROR_CANNOT_CONVERT_DATA;
-    }
-    nsCOMPtr<nsIProperties> attr_bag =
-                                 do_CreateInstance(NS_PROPERTIES_CONTRACTID);
-    NS_ENSURE_TRUE(attr_bag, NS_ERROR_INVALID_POINTER);
-    nsCAutoString attrList;
-    attrList.Append(Substring(tagpref,
-                              bracket + 1,
-                              tagpref.Length() - 2 - bracket));
-    char* attrs_lasts;
-    for (char* iAttr = PL_strtok_r(attrList.BeginWriting(),
-                                   ",", &attrs_lasts);
-         iAttr;
-         iAttr = PL_strtok_r(NULL, ",", &attrs_lasts))
-    {
-      attr_bag->Set(iAttr, 0);
-    }
-
-    nsIProperties* attr_bag_raw = attr_bag;
-    NS_ADDREF(attr_bag_raw);
-    mAllowedTags.Put(&tag_key, attr_bag_raw);
-  }
-
-  return NS_OK;
-}
-
-/*
-  might be useful:
-  htmlparser/public/nsHTMLTokens.h for tag categories
-*/
deleted file mode 100644
--- a/content/base/src/mozSanitizingSerializer.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 sw=2 et tw=80: */
-/* ***** 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.org HTML Sanitizer code.
- *
- * The Initial Developer of the Original Code is
- * Ben Bucksch <mozilla@bucksch.org>.
- * Portions created by the Initial Developer are Copyright (C) 2002
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Netscape
- *
- * 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 ***** */
-
-/*
- * A serializer and content sink that removes potentially insecure or
- * otherwise dangerous or offending HTML (eg for display of HTML
- * e-mail attachments or something).
- */
-
-#ifndef mozSanitizingSerializer_h__
-#define mozSanitizingSerializer_h__
-
-#include "mozISanitizingSerializer.h"
-#include "nsIContentSerializer.h"
-#include "nsIHTMLContentSink.h"
-#include "nsHTMLTags.h"
-#include "nsCOMPtr.h"
-#include "nsIParserService.h"
-#include "nsIContent.h"
-#include "nsIAtom.h"
-#include "nsString.h"
-#include "nsIParser.h"
-#include "nsHashtable.h"
-
-class mozSanitizingHTMLSerializer : public nsIContentSerializer,
-                                    public nsIHTMLContentSink,
-                                    public mozISanitizingHTMLSerializer
-{
-public:
-  mozSanitizingHTMLSerializer();
-  virtual ~mozSanitizingHTMLSerializer();
-  static bool ReleaseProperties(nsHashKey* key, void* data, void* closure);
-
-  NS_DECL_ISUPPORTS
-
-  // nsIContentSerializer
-  NS_IMETHOD Init(PRUint32 flags, PRUint32 dummy, const char* aCharSet, 
-                  bool aIsCopying, bool aIsWholeDocument);
-
-  NS_IMETHOD AppendText(nsIContent* aText, PRInt32 aStartOffset,
-                        PRInt32 aEndOffset, nsAString& aStr);
-  NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection,
-                                PRInt32 aStartOffset, PRInt32 aEndOffset,
-                                nsAString& aStr)
-                      { return NS_OK; }
-  NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI,
-                                         PRInt32 aStartOffset,
-                                         PRInt32 aEndOffset,
-                                         nsAString& aStr)
-                      { return NS_OK; }
-  NS_IMETHOD AppendComment(nsIContent* aComment, PRInt32 aStartOffset,
-                           PRInt32 aEndOffset, nsAString& aStr)
-                      { return NS_OK; }
-  NS_IMETHOD AppendDoctype(nsIContent *aDoctype, nsAString& aStr)
-                      { return NS_OK; }
-  NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
-                                mozilla::dom::Element* aOriginalElement,
-                                nsAString& aStr);
-  NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
-                              nsAString& aStr);
-  NS_IMETHOD Flush(nsAString& aStr);
-
-  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(nsParserBase* aParser) { return NS_OK; }
-  NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
-  NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
-  NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
-  virtual void FlushPendingNotifications(mozFlushType aType) { }
-  NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
-  virtual nsISupports *GetTarget() { return nsnull; }
-
-  // nsIHTMLContentSink
-  NS_IMETHOD OpenHead();
-  NS_IMETHOD IsEnabled(PRInt32 aTag, bool* aReturn);
-  NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode) { return NS_OK; }
-  NS_IMETHOD BeginContext(PRInt32 aPosition) { return NS_OK; }
-  NS_IMETHOD EndContext(PRInt32 aPosition) { return NS_OK; }
-  NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
-  NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
-  NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
-
-  // nsISanitizingHTMLSerializer
-  NS_IMETHOD Initialize(nsAString* aOutString,
-                        PRUint32 aFlags, const nsAString& allowedTags);
-
-protected:
-  nsresult ParsePrefs(const nsAString& aPref);
-  nsresult ParseTagPref(const nsCAutoString& tagpref);
-  bool IsAllowedTag(nsHTMLTag aTag);
-  bool IsAllowedAttribute(nsHTMLTag aTag, const nsAString& anAttributeName);
-  nsresult SanitizeAttrValue(nsHTMLTag aTag, const nsAString& attr_name,
-                             nsString& value /*inout*/);
-  nsresult SanitizeTextNode(nsString& value /*inout*/);
-  bool IsContainer(PRInt32 aId);
-  static PRInt32 GetIdForContent(nsIContent* aContent);
-  nsresult GetParserService(nsIParserService** aParserService);
-  nsresult DoOpenContainer(PRInt32 aTag);
-  nsresult DoCloseContainer(PRInt32 aTag);
-  nsresult DoAddLeaf(PRInt32 aTag, const nsAString& aText);
-  void Write(const nsAString& aString);
-
-protected:
-  PRInt32                      mFlags;
-  PRUint32                     mSkipLevel;
-  nsHashtable                  mAllowedTags;
-
-  nsRefPtr<mozilla::dom::Element> mElement;
-  nsAString*                   mOutputString;
-  nsIParserNode*               mParserNode;
-  nsCOMPtr<nsIParserService>   mParserService;
-};
-
-nsresult
-NS_NewSanitizingHTMLSerializer(nsIContentSerializer** aSerializer);
-
-#endif
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -173,16 +173,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsFocusManager.h"
 #include "nsTextEditorState.h"
 #include "nsIPluginHost.h"
 #include "nsICategoryManager.h"
 #include "nsIViewManager.h"
 #include "nsEventStateManager.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsParserConstants.h"
+#include "nsIWebNavigation.h"
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
@@ -5175,18 +5176,25 @@ nsContentUtils::SetDataTransferInEvent(n
     initialDataTransfer =
       new nsDOMDataTransfer(aDragEvent->message);
     NS_ENSURE_TRUE(initialDataTransfer, NS_ERROR_OUT_OF_MEMORY);
 
     // now set it in the drag session so we don't need to create it again
     dragSession->SetDataTransfer(initialDataTransfer);
   }
 
+  bool isCrossDomainSubFrameDrop = false;
+  if (aDragEvent->message == NS_DRAGDROP_DROP ||
+      aDragEvent->message == NS_DRAGDROP_DRAGDROP) {
+    isCrossDomainSubFrameDrop = CheckForSubFrameDrop(dragSession, aDragEvent);
+  }
+
   // each event should use a clone of the original dataTransfer.
   initialDataTransfer->Clone(aDragEvent->message, aDragEvent->userCancelled,
+                             isCrossDomainSubFrameDrop,
                              getter_AddRefs(aDragEvent->dataTransfer));
   NS_ENSURE_TRUE(aDragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY);
 
   // for the dragenter and dragover events, initialize the drop effect
   // from the drop action, which platform specific widget code sets before
   // the event is fired based on the keyboard state.
   if (aDragEvent->message == NS_DRAGDROP_ENTER ||
       aDragEvent->message == NS_DRAGDROP_OVER) {
@@ -5240,16 +5248,62 @@ nsContentUtils::FilterDropEffect(PRUint3
     return nsIDragService::DRAGDROP_ACTION_COPY;
   if (aEffectAllowed & nsIDragService::DRAGDROP_ACTION_LINK)
     return nsIDragService::DRAGDROP_ACTION_LINK;
   return nsIDragService::DRAGDROP_ACTION_NONE;
 }
 
 /* static */
 bool
+nsContentUtils::CheckForSubFrameDrop(nsIDragSession* aDragSession, nsDragEvent* aDropEvent)
+{
+  nsCOMPtr<nsIContent> target = do_QueryInterface(aDropEvent->originalTarget);
+  if (!target && !target->OwnerDoc()) {
+    return true;
+  }
+  
+  nsIDocument* targetDoc = target->OwnerDoc();
+  nsCOMPtr<nsIWebNavigation> twebnav = do_GetInterface(targetDoc->GetWindow());
+  nsCOMPtr<nsIDocShellTreeItem> tdsti = do_QueryInterface(twebnav);
+  if (!tdsti) {
+    return true;
+  }
+
+  PRInt32 type = -1;
+  if (NS_FAILED(tdsti->GetItemType(&type))) {
+    return true;
+  }
+
+  // Always allow dropping onto chrome shells.
+  if (type == nsIDocShellTreeItem::typeChrome) {
+    return false;
+  }
+
+  // If there is no source node, then this is a drag from another
+  // application, which should be allowed.
+  nsCOMPtr<nsIDOMDocument> sourceDocument;
+  aDragSession->GetSourceDocument(getter_AddRefs(sourceDocument));
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(sourceDocument);
+  if (doc) {
+    // Get each successive parent of the source document and compare it to
+    // the drop document. If they match, then this is a drag from a child frame.
+    do {
+      doc = doc->GetParentDocument();
+      if (doc == targetDoc) {
+        // The drag is from a child frame.
+        return true;
+      }
+    } while (doc);
+  }
+
+  return false;
+}
+
+/* static */
+bool
 nsContentUtils::URIIsLocalFile(nsIURI *aURI)
 {
   bool isFile;
   nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
 
   // Important: we do NOT test the entire URI chain here!
   return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
                                 nsIProtocolHandler::URI_IS_LOCAL_FILE,
@@ -5319,83 +5373,101 @@ nsContentUtils::GetCurrentJSContext()
   JSContext *cx = nsnull;
 
   sThreadJSContextStack->Peek(&cx);
 
   return cx;
 }
 
 /* static */
-void
+nsresult
 nsContentUtils::ASCIIToLower(nsAString& aStr)
 {
   PRUnichar* iter = aStr.BeginWriting();
   PRUnichar* end = aStr.EndWriting();
+  if (NS_UNLIKELY(!iter || !end)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
   while (iter != end) {
     PRUnichar c = *iter;
     if (c >= 'A' && c <= 'Z') {
       *iter = c + ('a' - 'A');
     }
     ++iter;
   }
+  return NS_OK;
 }
 
 /* static */
-void
+nsresult
 nsContentUtils::ASCIIToLower(const nsAString& aSource, nsAString& aDest)
 {
   PRUint32 len = aSource.Length();
   aDest.SetLength(len);
   if (aDest.Length() == len) {
     PRUnichar* dest = aDest.BeginWriting();
+    if (NS_UNLIKELY(!dest)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
     const PRUnichar* iter = aSource.BeginReading();
     const PRUnichar* end = aSource.EndReading();
     while (iter != end) {
       PRUnichar c = *iter;
       *dest = (c >= 'A' && c <= 'Z') ?
          c + ('a' - 'A') : c;
       ++iter;
       ++dest;
     }
-  }
+    return NS_OK;
+  }
+  return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* static */
-void
+nsresult
 nsContentUtils::ASCIIToUpper(nsAString& aStr)
 {
   PRUnichar* iter = aStr.BeginWriting();
   PRUnichar* end = aStr.EndWriting();
+  if (NS_UNLIKELY(!iter || !end)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
   while (iter != end) {
     PRUnichar c = *iter;
     if (c >= 'a' && c <= 'z') {
       *iter = c + ('A' - 'a');
     }
     ++iter;
   }
+  return NS_OK;
 }
 
 /* static */
-void
+nsresult
 nsContentUtils::ASCIIToUpper(const nsAString& aSource, nsAString& aDest)
 {
   PRUint32 len = aSource.Length();
   aDest.SetLength(len);
   if (aDest.Length() == len) {
     PRUnichar* dest = aDest.BeginWriting();
+    if (NS_UNLIKELY(!dest)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
     const PRUnichar* iter = aSource.BeginReading();
     const PRUnichar* end = aSource.EndReading();
     while (iter != end) {
       PRUnichar c = *iter;
       *dest = (c >= 'a' && c <= 'z') ?
          c + ('A' - 'a') : c;
       ++iter;
       ++dest;
     }
-  }
+    return NS_OK;
+  }
+  return NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* static */
 bool
 nsContentUtils::EqualsIgnoreASCIICase(const nsAString& aStr1,
                                       const nsAString& aStr2)
 {
   PRUint32 len = aStr1.Length();
--- a/content/base/src/nsTreeSanitizer.cpp
+++ b/content/base/src/nsTreeSanitizer.cpp
@@ -1374,34 +1374,41 @@ nsTreeSanitizer::SanitizeURL(mozilla::do
     nsContentUtils::TrimCharsInSet(kWhitespace, value);
 
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   PRUint32 flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL;
 
   nsCOMPtr<nsIURI> baseURI = aElement->GetBaseURI();
   nsCOMPtr<nsIURI> attrURI;
   nsresult rv = NS_NewURI(getter_AddRefs(attrURI), v, nsnull, baseURI);
-  if (NS_SUCCEEDED(rv)) {
-    rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags);
-  }
-  if (mCidEmbedsOnly &&
-      NS_SUCCEEDED(rv) &&
-      kNameSpaceID_None == aNamespace) {
-    if (nsGkAtoms::src == aLocalName || nsGkAtoms::background == aLocalName) {
-      bool isCid;
-      attrURI->SchemeIs("cid", &isCid);
-      if (!isCid) {
+  if (NS_SUCCEEDED(rv)) { 
+    if (mCidEmbedsOnly &&
+        kNameSpaceID_None == aNamespace) {
+      if (nsGkAtoms::src == aLocalName || nsGkAtoms::background == aLocalName) {
+        // comm-central uses a hack that makes nsIURIs created with cid: specs
+        // actually have an about:blank spec. Therefore, nsIURI facilities are
+        // useless for cid: when comm-central code is participating.
+        if (!(v.Length() > 4 &&
+              (v[0] == 'c' || v[0] == 'C') &&
+              (v[1] == 'i' || v[1] == 'I') &&
+              (v[2] == 'd' || v[2] == 'D') &&
+              v[3] == ':')) {
+          rv = NS_ERROR_FAILURE;
+        }
+      } else if (nsGkAtoms::cdgroup_ == aLocalName ||
+                 nsGkAtoms::altimg_ == aLocalName ||
+                 nsGkAtoms::definitionURL_ == aLocalName) {
+        // Gecko doesn't fetch these now and shouldn't in the future, but
+        // in case someone goofs with these in the future, let's drop them.
         rv = NS_ERROR_FAILURE;
+      } else {
+        rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags);
       }
-    } else if (nsGkAtoms::cdgroup_ == aLocalName ||
-               nsGkAtoms::altimg_ == aLocalName ||
-               nsGkAtoms::definitionURL_ == aLocalName) {
-      // Gecko doesn't fetch these now and shouldn't in the future, but
-      // in case someone goofs with these in the future, let's drop them.
-      rv = NS_ERROR_FAILURE;
+    } else {
+      rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags);
     }
   }
   if (NS_FAILED(rv)) {
     aElement->UnsetAttr(aNamespace, aLocalName, false);
     return true;
   }
   return false;
 }
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -92,16 +92,17 @@
 
 #include "gfxContext.h"
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxFont.h"
 #include "gfxBlur.h"
 #include "gfxUtils.h"
+#include "nsRenderingContext.h"
 
 #include "nsFrameManager.h"
 #include "nsFrameLoader.h"
 #include "nsBidi.h"
 #include "nsBidiPresUtils.h"
 #include "Layers.h"
 #include "CanvasUtils.h"
 #include "nsIMemoryReporter.h"
--- a/content/events/src/nsDOMDataTransfer.cpp
+++ b/content/events/src/nsDOMDataTransfer.cpp
@@ -37,29 +37,32 @@
 
 #include "mozilla/Util.h"
 
 #include "nsDOMDataTransfer.h"
 
 #include "prlog.h"
 #include "nsString.h"
 #include "nsIServiceManager.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsIVariant.h"
 #include "nsISupportsPrimitives.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsDOMLists.h"
 #include "nsGUIEvent.h"
 #include "nsDOMError.h"
 #include "nsIDragService.h"
 #include "nsIScriptableRegion.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsCRT.h"
 #include "nsIScriptObjectPrincipal.h"
+#include "nsIWebNavigation.h"
+#include "nsIDocShellTreeItem.h"
 
 using namespace mozilla;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMDataTransfer)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMDataTransfer)
   if (tmp->mFiles) {
     tmp->mFiles->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFiles)
@@ -92,51 +95,55 @@ const char nsDOMDataTransfer::sEffects[8
 nsDOMDataTransfer::nsDOMDataTransfer()
   : mEventType(NS_DRAGDROP_START),
     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
     mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED),
     mCursorState(false),
     mReadOnly(false),
     mIsExternal(false),
     mUserCancelled(false),
+    mIsCrossDomainSubFrameDrop(false),
     mDragImageX(0),
     mDragImageY(0)
 {
 }
 
 nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType)
   : mEventType(aEventType),
     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
     mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED),
     mCursorState(false),
     mReadOnly(true),
     mIsExternal(true),
     mUserCancelled(false),
+    mIsCrossDomainSubFrameDrop(false),
     mDragImageX(0),
     mDragImageY(0)
 {
   CacheExternalFormats();
 }
 
 nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType,
                                      const PRUint32 aEffectAllowed,
                                      bool aCursorState,
                                      bool aIsExternal,
                                      bool aUserCancelled,
+                                     bool aIsCrossDomainSubFrameDrop,
                                      nsTArray<nsTArray<TransferItem> >& aItems,
                                      nsIDOMElement* aDragImage,
                                      PRUint32 aDragImageX,
                                      PRUint32 aDragImageY)
   : mEventType(aEventType),
     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
     mEffectAllowed(aEffectAllowed),
     mCursorState(aCursorState),
     mReadOnly(true),
     mIsExternal(aIsExternal),
     mUserCancelled(aUserCancelled),
+    mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop),
     mItems(aItems),
     mDragImage(aDragImage),
     mDragImageX(aDragImageX),
     mDragImageY(aDragImageY)
 {
   // The items are copied from aItems into mItems. There is no need to copy
   // the actual data in the items as the data transfer will be read only. The
   // draggesture and dragstart events are the only times when items are
@@ -325,17 +332,20 @@ nsDOMDataTransfer::GetData(const nsAStri
 
   if (data) {
     nsAutoString stringdata;
     data->GetAsAString(stringdata);
 
     // for the URL type, parse out the first URI from the list. The URIs are
     // separated by newlines
     nsAutoString lowercaseFormat;
-    nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
+    rv = nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
     
     if (lowercaseFormat.EqualsLiteral("url")) {
       PRInt32 lastidx = 0, idx;
       PRInt32 length = stringdata.Length();
       while (lastidx < length) {
         idx = stringdata.FindChar('\n', lastidx);
         // lines beginning with # are comments
         if (stringdata[lastidx] == '#') {
@@ -458,22 +468,26 @@ nsDOMDataTransfer::MozGetDataAt(const ns
   if (aIndex >= mItems.Length())
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
 
   nsAutoString format;
   GetRealFormat(aFormat, format);
 
   nsTArray<TransferItem>& item = mItems[aIndex];
 
-  // allow access to any data in the drop and dragdrop events, or if the
-  // UniversalXPConnect privilege is set, otherwise only allow access to
-  // data from the same principal.
+  // Check if the caller is allowed to access the drag data. Callers with
+  // UniversalXPConnect privileges can always read the data. During the
+  // drop event, allow retrieving the data except in the case where the
+  // source of the drag is in a child frame of the caller. In that case,
+  // we only allow access to data of the same principal. During other events,
+  // only allow access to the data with the same principal.
   nsIPrincipal* principal = nsnull;
-  if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
-      !nsContentUtils::CallerHasUniversalXPConnect()) {
+  if (mIsCrossDomainSubFrameDrop ||
+      (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
+       !nsContentUtils::CallerHasUniversalXPConnect())) {
     nsresult rv = NS_OK;
     principal = GetCurrentPrincipal(&rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   PRUint32 count = item.Length();
   for (PRUint32 i = 0; i < count; i++) {
     TransferItem& formatitem = item[i];
@@ -610,32 +624,38 @@ nsDOMDataTransfer::SetDragImage(nsIDOMEl
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDataTransfer::AddElement(nsIDOMElement* aElement)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
 
+  if (aElement) {
+    nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
+    NS_ENSURE_TRUE(content, NS_ERROR_INVALID_ARG);
+  }
+
   if (mReadOnly)
     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
 
   mDragTarget = do_QueryInterface(aElement);
 
   return NS_OK;
 }
 
 nsresult
 nsDOMDataTransfer::Clone(PRUint32 aEventType, bool aUserCancelled,
+                         bool aIsCrossDomainSubFrameDrop,
                          nsIDOMDataTransfer** aNewDataTransfer)
 {
   nsDOMDataTransfer* newDataTransfer =
     new nsDOMDataTransfer(aEventType, mEffectAllowed, mCursorState,
-                          mIsExternal, aUserCancelled, mItems,
-                          mDragImage, mDragImageX, mDragImageY);
+                          mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop,
+                          mItems, mDragImage, mDragImageX, mDragImageY);
   NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_OUT_OF_MEMORY);
 
   *aNewDataTransfer = newDataTransfer;
   NS_ADDREF(*aNewDataTransfer);
   return NS_OK;
 }
 
 void
--- a/content/events/src/nsDOMDataTransfer.h
+++ b/content/events/src/nsDOMDataTransfer.h
@@ -95,16 +95,17 @@ protected:
 
   // this constructor is used only by the Clone method to copy the fields as
   // needed to a new data transfer.
   nsDOMDataTransfer(PRUint32 aEventType,
                     const PRUint32 aEffectAllowed,
                     bool aCursorState,
                     bool aIsExternal,
                     bool aUserCancelled,
+                    bool aIsCrossDomainSubFrameDrop,
                     nsTArray<nsTArray<TransferItem> >& aItems,
                     nsIDOMElement* aDragImage,
                     PRUint32 aDragImageX,
                     PRUint32 aDragImageY);
 
   ~nsDOMDataTransfer()
   {
     if (mFiles) {
@@ -188,16 +189,20 @@ protected:
 
   // true for drags started without a data transfer, for example, those from
   // another application.
   bool mIsExternal;
 
   // true if the user cancelled the drag. Used only for the dragend event.
   bool mUserCancelled;
 
+  // true if this is a cross-domain drop from a subframe where access to the
+  // data should be prevented
+  bool mIsCrossDomainSubFrameDrop;
+
   // array of items, each containing an array of format->data pairs
   nsTArray<nsTArray<TransferItem> > mItems;
 
   // array of files, containing only the files present in the dataTransfer
   nsRefPtr<nsDOMFileList> mFiles;
 
   // the target of the drag. The drag and dragend events will fire at this.
   nsCOMPtr<nsIDOMElement> mDragTarget;
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -347,18 +347,20 @@ nsGenericHTMLElement::SetAttribute(const
 
   if (!name) {
     nsresult rv = nsContentUtils::CheckQName(aName, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIAtom> nameAtom;
     if (IsInHTMLDocument()) {
       nsAutoString lower;
-      nsContentUtils::ASCIIToLower(aName, lower);
-      nameAtom = do_GetAtom(lower);
+      rv = nsContentUtils::ASCIIToLower(aName, lower);
+      if (NS_SUCCEEDED(rv)) {
+        nameAtom = do_GetAtom(lower);
+      }
     }
     else {
       nameAtom = do_GetAtom(aName);
     }
     NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
 
     return SetAttr(kNameSpaceID_None, nameAtom, aValue, true);
   }
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -321,17 +321,20 @@ nsHTMLCanvasElement::ToDataURLImpl(const
 
   nsIntSize size = GetWidthHeight();
   if (size.height == 0 || size.width == 0) {
     aDataURL = NS_LITERAL_STRING("data:,");
     return NS_OK;
   }
 
   nsAutoString type;
-  nsContentUtils::ASCIIToLower(aMimeType, type);
+  nsresult rv = nsContentUtils::ASCIIToLower(aMimeType, type);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
   nsAutoString params;
 
   // Quality parameter is only valid for the image/jpeg MIME type
   if (type.EqualsLiteral("image/jpeg")) {
     PRUint16 vartype;
 
     if (aEncoderOptions &&
@@ -362,18 +365,17 @@ nsHTMLCanvasElement::ToDataURLImpl(const
                                                     paramString.Length() - 
                                                     mozParseOptions.Length());
       params.Append(parseOptions);
       usingCustomParseOptions = true;
     }
   }
 
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = ExtractData(type, params, getter_AddRefs(stream),
-                            fallbackToPNG);
+  rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
 
   // If there are unrecognized custom parse options, we should fall back to 
   // the default values for the encoder without any options at all.
   if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
     fallbackToPNG = false;
     rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
   }
 
--- a/content/html/content/test/file_fullscreen-api-keys.html
+++ b/content/html/content/test/file_fullscreen-api-keys.html
@@ -10,17 +10,17 @@ Test that restricted key pressed drop do
   <title>Test for Bug 545812</title>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <style>
   body {
     background-color: black;
   }
   </style>
 </head>
-<body onload="document.body.mozRequestFullScreen();">
+<body>
 
 <script type="application/javascript">
 
 /** Test for Bug 545812 **/
 
 // List of key codes which should exit full-screen mode.
 var keyList = [
   { code: "VK_ESCAPE", suppressed: true},
@@ -87,34 +87,41 @@ function testScriptInitiatedKeyEvents() 
   
   ok(gKeyReceived, "dispatchEvent should dispatch events synchronously");
   ok(document.mozFullScreen,
      "Should remain in full-screen mode for script initiated key events for " + gKeyName);
 }
 
 function testNextKey() {
   if (!document.mozFullScreen) {
+    document.addEventListener("mozfullscreenchange", reallyTestNextKey, false);
     document.body.mozRequestFullScreen();
   }
-  // mozRequestFullScreen() is async...
-  setTimeout(
-    function() {
-      ok(document.mozFullScreen, "Must be in full-screen mode");
+  else {
+    reallyTestNextKey();
+  }
+}
+
+function reallyTestNextKey() {
+  document.removeEventListener("mozfullscreenchange", reallyTestNextKey, false);
 
-      gKeyName = keyList[gKeyTestIndex].code;
-      gKeyCode = KeyEvent["DOM_" + gKeyName];
-      gKeySuppressed = keyList[gKeyTestIndex].suppressed;
-      gKeyTestIndex++;
+  ok(document.mozFullScreen, "Must be in full-screen mode");
 
-      testScriptInitiatedKeyEvents();
-      testTrustedKeyEvents();
-    }, 0);
+  gKeyName = keyList[gKeyTestIndex].code;
+  gKeyCode = KeyEvent["DOM_" + gKeyName];
+  gKeySuppressed = keyList[gKeyTestIndex].suppressed;
+  gKeyTestIndex++;
+
+  testScriptInitiatedKeyEvents();
+  testTrustedKeyEvents();
 }
 
 window.addEventListener("keydown", keyHandler, true);
 window.addEventListener("keyup", keyHandler, true);
 window.addEventListener("keypress", keyHandler, true);
-setTimeout(testNextKey, 0);
 
+function begin() {
+  testNextKey();
+}
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/file_fullscreen-api.html
+++ b/content/html/content/test/file_fullscreen-api.html
@@ -11,17 +11,17 @@ Test DOM full-screen API.
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <style>
   body {
     background-color: black;
   }
   </style>
 </head>
-<body onload="start();">
+<body>
 <script type="application/javascript">
 
 /** Test for Bug 545812 **/
 
 function ok(condition, msg) {
   opener.ok(condition, "[fullscreen] " + msg);
 }
 
@@ -42,18 +42,16 @@ var iframe = null;
 var outOfDocElement = null;
 var inDocElement = null;
 var container = null;
 var button = null;
 var fullScreenChangeCount = 0;
 var fullscreendenied = false;
 var fullScreenErrorRun = false;
 
-document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
-
 function sendMouseClick(element) {
   synthesizeMouseAtCenter(element, {});
 }
 
 function setRequireTrustedContext(value) {
   opener.SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", value);
 }
 
@@ -227,19 +225,20 @@ function fullScreenChange(event) {
     }
     default: {
       ok(false, "Should not receive any more fullscreenchange events!");
     }
   }
   fullScreenChangeCount++;
 }
 
+document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
 document.addEventListener("mozfullscreenchange", fullScreenChange, false);
 
-function start() {
-  SimpleTest.waitForFocus(function() {fullScreenElement().mozRequestFullScreen();});
+function begin() {
+  fullScreenElement().mozRequestFullScreen();
 }
 
 </script>
 </pre>
 <div id="full-screen-element"></div>
 </body>
 </html>
--- a/content/html/content/test/file_fullscreen-denied.html
+++ b/content/html/content/test/file_fullscreen-denied.html
@@ -10,17 +10,17 @@ Test DOM full-screen API.
   <title>Test for Bug 545812</title>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <style>
   body {
     background-color: black;
   }
   </style>
 </head>
-<body onload="run();">
+<body>
 
 <script type="application/javascript">
 
 /** Test for Bug 545812 **/
 
 function ok(condition, msg) {
   opener.ok(condition, "[denied] " + msg);
 }
@@ -30,17 +30,17 @@ function is(a, b, msg) {
 }
 
 var fullscreendenied = false;
 
 document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
 
 var gotFullScreenChange = false;
 
-function run() {
+function begin() {
   document.addEventListener("mozfullscreenchange",
     function() {
       ok(false, "Should never receive a mozfullscreenchange event in the main window.");
       gotFullScreenChange = true;
     },
     false);
 
   // Request full-screen from a non trusted context (this script isn't a user
--- a/content/html/content/test/file_fullscreen-esc-exit.html
+++ b/content/html/content/test/file_fullscreen-esc-exit.html
@@ -11,17 +11,17 @@ exit DOM full-screen mode.
   <title>Test for Bug 700764</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <style>
   body:-moz-full-screen, div:-moz-full-screen {
     background-color: red;
   }
   </style>
 </head>
-<body onload="startTest();">
+<body>
 
 <script type="application/javascript">
 
 function ok(condition, msg) {
   opener.ok(condition, "[esc-exit] " + msg);
 }
 
 function is(a, b, msg) {
@@ -44,19 +44,19 @@ function fullscreenchange1(event) {
 function fullscreenchange2(event) {
   document.removeEventListener("mozfullscreenchange", fullscreenchange2, false);
   ok(document.getElementById("subdoc").contentWindow.escKeySent, "Should have sent ESC key press.");
   ok(!document.getElementById("subdoc").contentWindow.escKeyReceived, "ESC key press to exit should not be delivered.");
   ok(!document.mozFullScreen, "Should have left full-screen mode on ESC key press");
   finish();
 }
 
-function startTest() {
+function begin() {
   document.addEventListener("mozfullscreenchange", fullscreenchange1, false);
-  SimpleTest.waitForFocus(function() {document.body.mozRequestFullScreen();});
+  document.body.mozRequestFullScreen();
 }
 
 </script>
 
 <!-- This subframe conducts the test. -->
 <iframe id="subdoc" src="file_fullscreen-esc-exit-inner.html"></iframe>
 
 </pre>
--- a/content/html/content/test/file_fullscreen-hidden.html
+++ b/content/html/content/test/file_fullscreen-hidden.html
@@ -3,34 +3,34 @@
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=697636
 -->
 <head>
   <title>Test for Bug 697636</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
-<body onload="boom();">
+<body>
 
 <iframe id="f" src="data:text/html,<body text=green>1" mozallowfullscreen></iframe>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=697636">Mozilla Bug 697636</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 697636 **/
 
 var frameWin;
 var e1;
 
-function boom()
+function begin()
 {
   frameWin = document.getElementById("f").contentWindow;
   e1 = frameWin.document.documentElement;
   frameWin.location = "data:text/html,<body text=blue onload='parent.b2()'>2";
 }
 
 function b2()
 {
--- a/content/html/content/test/file_fullscreen-navigation.html
+++ b/content/html/content/test/file_fullscreen-navigation.html
@@ -3,17 +3,17 @@
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=685402
 -->
 <head>
   <title>Test for Bug 685402</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
-<body onload="boom();" style="background-color: gray;">
+<body style="background-color: gray;">
 
 <iframe id="f" src="data:text/html,<body text=green>1" mozallowfullscreen></iframe>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=685402">Mozilla Bug 685402</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
@@ -22,26 +22,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 685402 **/
 
 var frameWin;
 var e1;
 var prevEnabled;
 var prevTrusted;
 
-function boom()
+function begin()
 {
   frameWin = document.getElementById("f").contentWindow;
   e1 = frameWin.document.body;
+  document.addEventListener("mozfullscreenchange", function onfullscreen() {
+    document.removeEventListener("mozfullscreenchange", onfullscreen, false);
+    opener.ok(document.mozFullScreen, "[navigation] Request should be granted");
+    frameWin.location = "data:text/html,<body text=blue onload='parent.b2()'>2";
+  }, false);
+
   e1.mozRequestFullScreen();
-  setTimeout(
-    function() {
-      opener.ok(document.mozFullScreen, "[navigation] Request should be granted");
-      frameWin.location = "data:text/html,<body text=blue onload='parent.b2()'>2";
-    }, 0);
 }
 
 function b2()
 {
   opener.ok(!document.mozFullScreen, "[navigation] Should have left full-screen due to navigation.");
   opener.nextTest();
 }
 
--- a/content/html/content/test/file_fullscreen-plugins.html
+++ b/content/html/content/test/file_fullscreen-plugins.html
@@ -16,17 +16,17 @@ Test plugins with DOM full-screen API:
   <title>Test for Bug 545812</title>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <style>
   body:-moz-full-screen, div:-moz-full-screen {
     background-color: red;
   }
   </style>
 </head>
-<body onload="scheduleTest();">
+<body>
 
 
 <!-- Windowed plugin, focusing should revoke full-screen. -->
 <embed id="windowed-plugin" type="application/x-test" style="width:200px;height:100px;" wmode="window"></embed>
 
 <!-- Windowless plugin, focusing should not revoke full-screen. -->
 <embed id="windowless-plugin" type="application/x-test" style="width:200px;height:100px;"></embed>
 
@@ -54,17 +54,17 @@ function is(a, b, msg) {
 function e(id) {
   return document.getElementById(id);
 }
 
 const isMacOs = navigator.appVersion.indexOf("Macintosh") != -1;
 
 var windowedPlugin = null;
 
-function scheduleTest() {
+function begin() {
   // Delay test startup long enough for the windowed plugin in the subframe to
   // start up and create its window.
   opener.SimpleTest.executeSoon(function() {
     opener.SimpleTest.executeSoon(function() {
       startTest();
     })
   });
 }
--- a/content/html/content/test/file_fullscreen-rollback.html
+++ b/content/html/content/test/file_fullscreen-rollback.html
@@ -15,17 +15,17 @@ Tests:
 * Removing FSE should fully-exit full-screen.
 
 
 -->
 <head>
   <title>Test for Bug 700764</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 </head>
-<body onload="start();">
+<body>
 
 <div id="fse">
   <div id="fse-inner">
     <iframe id="subdoc" mozallowfullscreen src="data:text/html,<html><body bgcolor='black'></body></html>"></iframe>
   </div>
 </div>
 
 <div id="non-fse"></div>
@@ -49,23 +49,19 @@ function addListener(type, f) {
 function removeListener(type, f) {
   document.removeEventListener("mozfullscreen" + type, f, false);
 }
 
 function e(id) {
   return document.getElementById(id);
 }
 
-function start() {
-  SimpleTest.waitForFocus(
-    function() {
-      addListener("change", change1);
-      e("fse").mozRequestFullScreen();
-    }
-  );
+function begin() {
+  addListener("change", change1);
+  e("fse").mozRequestFullScreen();
 }
 
 function change1() {
   removeListener("change", change1);
   addListener("error", error1);
   is(document.mozFullScreenElement, e("fse"), "Body should be FSE");
   
   // Request full-screen from element not descendent from current FSE.
--- a/content/html/content/test/test_fullscreen-api.html
+++ b/content/html/content/test/test_fullscreen-api.html
@@ -19,22 +19,20 @@
 
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Tests for Bug 545812 **/
 
 // Ensure the full-screen api is enabled, and will be disabled on test exit.
-var prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
 SpecialPowers.setBoolPref("full-screen-api.enabled", true);
 
 // Disable the requirement for trusted contexts only, so the tests are easier
 // to write.
-var prevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
 SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
 
 // Run the tests which go full-screen in new windows, as mochitests normally
 // run in an iframe, which by default will not have the mozallowfullscreen
 // attribute set, so full-screen won't work.
 var gTestWindows = [
   "file_fullscreen-rollback.html",
   "file_fullscreen-esc-exit.html",
@@ -45,32 +43,54 @@ var gTestWindows = [
   "file_fullscreen-hidden.html",
   "file_fullscreen-navigation.html"
 ];
 
 var testWindow = null;
 var gTestIndex = 0;
 
 const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
+const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
 
 function nextTest() {
   if (isWinXP) {
     todo(false, "Can't reliably run full-screen tests on Windows XP due to bug 704010");
     SimpleTest.finish();
     return;
   }
   if (testWindow) {
     testWindow.close();
+    if (isOSXLion) {
+      // On OS X Lion, tests cause problems. Timeouts are a bad way to get around
+      // the problem and may lead to future [orange], but they are the only option
+      // at this point.
+      SimpleTest.waitForFocus(function() { setTimeout(runNextTest, 3000); });
+      return;
+    }
   }
+  runNextTest();
+}
+
+function runNextTest() {
   if (gTestIndex < gTestWindows.length) {
     testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500");
+    // We'll wait for the window to load, then make sure our window is refocused
+    // before starting the test, which will get kicked off on "focus".
+    // This ensures that we're essentially back on the primary "desktop" on
+    // OS X Lion before we run the test.
+    testWindow.addEventListener("load", function onload() {
+      testWindow.removeEventListener("load", onload, false);
+      SimpleTest.waitForFocus(function() {
+        SimpleTest.waitForFocus(testWindow.begin, testWindow);
+      });
+    }, false);
     gTestIndex++;
   } else {
-    SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled);
-    SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted);	
+    SpecialPowers.clearUserPref("full-screen-api.enabled");
+    SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
     SimpleTest.finish();
   }
 }
 
 try {
   window.fullScreen = true;
 } catch (e) {
 }
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -402,17 +402,20 @@ HTMLContentSink::AddAttributes(const nsI
     i = ac - 1;
     limit = -1;
     step = -1;
   }
   
   nsAutoString key;
   for (; i != limit; i += step) {
     // Get lower-cased key
-    nsContentUtils::ASCIIToLower(aNode.GetKeyAt(i), key);
+    nsresult rv = nsContentUtils::ASCIIToLower(aNode.GetKeyAt(i), key);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
 
     nsCOMPtr<nsIAtom> keyAtom = do_GetAtom(key);
 
     if (aCheckIfPresent && aContent->HasAttr(kNameSpaceID_None, keyAtom)) {
       continue;
     }
 
     // Get value and remove mandatory quotes
--- a/content/smil/nsSMILAnimationController.cpp
+++ b/content/smil/nsSMILAnimationController.cpp
@@ -394,18 +394,24 @@ nsSMILAnimationController::DoSample(bool
     NS_ERROR("Shouldn't be sampling after document has disconnected");
     return;
   }
 
   mResampleNeeded = false;
   // Set running sample flag -- do this before flushing styles so that when we
   // flush styles we don't end up requesting extra samples
   mRunningSample = true;
+  nsCOMPtr<nsIDocument> kungFuDeathGrip(mDocument);  // keeps 'this' alive too
   mDocument->FlushPendingNotifications(Flush_Style);
 
+  // WARNING: 
+  // WARNING: the above flush may have destroyed the pres shell and/or
+  // WARNING: frames and other layout related objects.
+  // WARNING:
+  
   // STEP 1: Bring model up to date
   // (i)  Rewind elements where necessary
   // (ii) Run milestone samples
   RewindElements();
   DoMilestoneSamples();
 
   // STEP 2: Sample the child time containers
   //
--- a/content/smil/nsSMILAnimationController.h
+++ b/content/smil/nsSMILAnimationController.h
@@ -90,27 +90,30 @@ public:
 
   // Methods for registering and enumerating animation elements
   void RegisterAnimationElement(nsISMILAnimationElement* aAnimationElement);
   void UnregisterAnimationElement(nsISMILAnimationElement* aAnimationElement);
 
   // Methods for resampling all animations
   // (A resample performs the same operations as a sample but doesn't advance
   // the current time and doesn't check if the container is paused)
+  // This will flush pending style changes for the document.
   void Resample() { DoSample(false); }
 
   void SetResampleNeeded()
   {
     if (!mRunningSample) {
       if (!mResampleNeeded) {
         FlagDocumentNeedsFlush();
       }
       mResampleNeeded = true;
     }
   }
+
+  // This will flush pending style changes for the document.
   void FlushResampleRequests()
   {
     if (!mResampleNeeded)
       return;
 
     Resample();
   }
 
--- a/content/svg/content/src/nsSVGDataParser.cpp
+++ b/content/svg/content/src/nsSVGDataParser.cpp
@@ -47,16 +47,18 @@
   *
   */
 
 
 #include "nsSVGDataParser.h"
 #include "prdtoa.h"
 #include "nsSVGUtils.h"
 #include "nsMathUtils.h"
+#include "nsMemory.h"
+#include "nsReadableUtils.h"
 #include <stdlib.h>
 #include <math.h>
 
 //----------------------------------------------------------------------
 // public interface
 
 nsresult
 nsSVGDataParser::Parse(const nsAString &aValue)
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -3795,71 +3795,43 @@ nsSVGFEMorphologyElement::Filter(nsSVGFi
   }
   if (rx == 0 && ry == 0) {
     return NS_OK;
   }
 
   PRUint8* sourceData = aSources[0]->mImage->Data();
   PRUint8* targetData = aTarget->mImage->Data();
   PRUint32 stride = aTarget->mImage->Stride();
-  PRUint32 xExt[4], yExt[4];  // X, Y indices of RGBA extrema
   PRUint8 extrema[4];         // RGBA magnitude of extrema
   PRUint16 op = mEnumAttributes[OPERATOR].GetAnimValue();
 
-  /* Scan the kernel for each pixel to determine max/min RGBA values.  Note that
-   * as we advance in the x direction, each kernel overlaps the previous kernel.
-   * Thus, we can avoid iterating over the entire kernel by comparing the
-   * leading edge of the new kernel against the extrema found in the previous
-   * kernel.   We must still scan the entire kernel if the previous extrema do
-   * not fall within the current kernel or if we are starting a new row.
-   */
+  // Scan the kernel for each pixel to determine max/min RGBA values.
   for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
     PRUint32 startY = NS_MAX(0, y - ry);
     // We need to read pixels not just in 'rect', which is limited to
     // the dirty part of our filter primitive subregion, but all pixels in
     // the given radii from the source surface, so use the surface size here.
     PRUint32 endY = NS_MIN(y + ry, instance->GetSurfaceHeight() - 1);
     for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
       PRUint32 startX = NS_MAX(0, x - rx);
       PRUint32 endX = NS_MIN(x + rx, instance->GetSurfaceWidth() - 1);
       PRUint32 targIndex = y * stride + 4 * x;
 
-      // We need to scan the entire kernel
-      if (x == rect.x || xExt[0]  <= startX || xExt[1] <= startX ||
-          xExt[2] <= startX || xExt[3] <= startX) {
-        PRUint32 i;
-        for (i = 0; i < 4; i++) {
-          extrema[i] = sourceData[targIndex + i];
-        }
-        for (PRUint32 y1 = startY; y1 <= endY; y1++) {
-          for (PRUint32 x1 = startX; x1 <= endX; x1++) {
-            for (i = 0; i < 4; i++) {
-              PRUint8 pixel = sourceData[y1 * stride + 4 * x1 + i];
-              if ((extrema[i] >= pixel &&
-                   op == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) ||
-                  (extrema[i] <= pixel &&
-                   op == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE)) {
-                extrema[i] = pixel;
-                xExt[i] = x1;
-                yExt[i] = y1;
-              }
-            }
-          }
-        }
-      } else { // We only need to look at the newest column
-        for (PRUint32 y1 = startY; y1 <= endY; y1++) {
+      for (PRUint32 i = 0; i < 4; i++) {
+        extrema[i] = sourceData[targIndex + i];
+      }
+      for (PRUint32 y1 = startY; y1 <= endY; y1++) {
+        for (PRUint32 x1 = startX; x1 <= endX; x1++) {
           for (PRUint32 i = 0; i < 4; i++) {
-            PRUint8 pixel = sourceData[y1 * stride + 4 * endX + i];
-            if ((extrema[i] >= pixel &&
+            PRUint8 pixel = sourceData[y1 * stride + 4 * x1 + i];
+            if ((extrema[i] > pixel &&
                  op == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) ||
-                (extrema[i] <= pixel &&
+                (extrema[i] < pixel &&
                  op == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE)) {
-                extrema[i] = pixel;
-                xExt[i] = endX;
-                yExt[i] = y1;
+              extrema[i] = pixel;
             }
           }
         }
       }
       targetData[targIndex  ] = extrema[0];
       targetData[targIndex+1] = extrema[1];
       targetData[targIndex+2] = extrema[2];
       targetData[targIndex+3] = extrema[3];
@@ -5114,24 +5086,21 @@ nsSVGFELightingElement::Filter(nsSVGFilt
 
       if (spotLight) {
         float S[3];
         S[0] = pointsAt[0] - lightPos[0];
         S[1] = pointsAt[1] - lightPos[1];
         S[2] = pointsAt[2] - lightPos[2];
         NORMALIZE(S);
         float dot = -DOT(L, S);
-        if (dot < cosConeAngle) {
-          color = NS_RGB(0, 0, 0);
-        } else {
-          float tmp = pow(dot, specularExponent);
-          color = NS_RGB(PRUint8(NS_GET_R(lightColor) * tmp),
-                         PRUint8(NS_GET_G(lightColor) * tmp),
-                         PRUint8(NS_GET_B(lightColor) * tmp));
-        }
+        if (dot < cosConeAngle) dot = 0;
+        float tmp = pow(dot, specularExponent);
+        color = NS_RGB(PRUint8(NS_GET_R(lightColor) * tmp),
+                       PRUint8(NS_GET_G(lightColor) * tmp),
+                       PRUint8(NS_GET_B(lightColor) * tmp));
       } else {
         color = lightColor;
       }
 
       LightPixel(N, L, color, targetData + index);
     }
   }
 
@@ -5288,29 +5257,24 @@ nsSVGFEDiffuseLightingElement::Attribute
 
 void
 nsSVGFEDiffuseLightingElement::LightPixel(const float *N, const float *L,
                                           nscolor color, PRUint8 *targetData)
 {
   float diffuseNL =
     mNumberAttributes[DIFFUSE_CONSTANT].GetAnimValue() * DOT(N, L);
 
-  if (diffuseNL > 0) {
-    targetData[GFX_ARGB32_OFFSET_B] =
-      NS_MIN(PRUint32(diffuseNL * NS_GET_B(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_G] =
-      NS_MIN(PRUint32(diffuseNL * NS_GET_G(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_R] =
-      NS_MIN(PRUint32(diffuseNL * NS_GET_R(color)), 255U);
-  } else {
-    targetData[GFX_ARGB32_OFFSET_B] = 0;
-    targetData[GFX_ARGB32_OFFSET_G] = 0;
-    targetData[GFX_ARGB32_OFFSET_R] = 0;
-  }
-
+  if (diffuseNL < 0) diffuseNL = 0;
+
+  targetData[GFX_ARGB32_OFFSET_B] =
+    NS_MIN(PRUint32(diffuseNL * NS_GET_B(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_G] =
+    NS_MIN(PRUint32(diffuseNL * NS_GET_G(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_R] =
+    NS_MIN(PRUint32(diffuseNL * NS_GET_R(color)), 255U);
   targetData[GFX_ARGB32_OFFSET_A] = 255;
 }
 
 //---------------------SpecularLighting------------------------
 
 typedef nsSVGFELightingElement nsSVGFESpecularLightingElementBase;
 
 class nsSVGFESpecularLightingElement : public nsSVGFESpecularLightingElementBase,
@@ -5455,37 +5419,34 @@ nsSVGFESpecularLightingElement::LightPix
   H[0] = L[0];
   H[1] = L[1];
   H[2] = L[2] + 1;
   NORMALIZE(H);
 
   float kS = mNumberAttributes[SPECULAR_CONSTANT].GetAnimValue();
   float dotNH = DOT(N, H);
 
-  if (dotNH > 0 && kS > 0) {
-    float specularNH =
-      kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue());
-
-    targetData[GFX_ARGB32_OFFSET_B] =
-      NS_MIN(PRUint32(specularNH * NS_GET_B(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_G] =
-      NS_MIN(PRUint32(specularNH * NS_GET_G(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_R] =
-      NS_MIN(PRUint32(specularNH * NS_GET_R(color)), 255U);
-
-    targetData[GFX_ARGB32_OFFSET_A] =
-      NS_MAX(targetData[GFX_ARGB32_OFFSET_B],
-             NS_MAX(targetData[GFX_ARGB32_OFFSET_G],
-                    targetData[GFX_ARGB32_OFFSET_R]));
-  } else {
-    targetData[GFX_ARGB32_OFFSET_B] = 0;
-    targetData[GFX_ARGB32_OFFSET_G] = 0;
-    targetData[GFX_ARGB32_OFFSET_R] = 0;
-    targetData[GFX_ARGB32_OFFSET_A] = 255;
-  }
+  bool invalid = dotNH <= 0 || kS <= 0;
+  kS *= invalid ? 0 : 1;
+  PRUint8 minAlpha = invalid ? 255 : 0;
+
+  float specularNH =
+    kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue());
+
+  targetData[GFX_ARGB32_OFFSET_B] =
+    NS_MIN(PRUint32(specularNH * NS_GET_B(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_G] =
+    NS_MIN(PRUint32(specularNH * NS_GET_G(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_R] =
+    NS_MIN(PRUint32(specularNH * NS_GET_R(color)), 255U);
+
+  targetData[GFX_ARGB32_OFFSET_A] =
+    NS_MAX(minAlpha, NS_MAX(targetData[GFX_ARGB32_OFFSET_B],
+                            NS_MAX(targetData[GFX_ARGB32_OFFSET_G],
+                                   targetData[GFX_ARGB32_OFFSET_R])));
 }
 
 //---------------------Image------------------------
 
 nsSVGElement::StringInfo nsSVGFEImageElement::sStringInfo[2] =
 {
   { &nsGkAtoms::result, kNameSpaceID_None, true },
   { &nsGkAtoms::href, kNameSpaceID_XLink, true }
@@ -5984,16 +5945,18 @@ nsSVGFEDisplacementMapElement::Filter(ns
   PRInt32 width = instance->GetSurfaceWidth();
   PRInt32 height = instance->GetSurfaceHeight();
 
   PRUint8* sourceData = aSources[0]->mImage->Data();
   PRUint8* displacementData = aSources[1]->mImage->Data();
   PRUint8* targetData = aTarget->mImage->Data();
   PRUint32 stride = aTarget->mImage->Stride();
 
+  static PRUint8 dummyData[4] = { 0, 0, 0, 0 };
+
   static const PRUint16 channelMap[5] = {
                              0,
                              GFX_ARGB32_OFFSET_R,
                              GFX_ARGB32_OFFSET_G,
                              GFX_ARGB32_OFFSET_B,
                              GFX_ARGB32_OFFSET_A };
   PRUint16 xChannel = channelMap[mEnumAttributes[CHANNEL_X].GetAnimValue()];
   PRUint16 yChannel = channelMap[mEnumAttributes[CHANNEL_Y].GetAnimValue()];
@@ -6006,23 +5969,30 @@ nsSVGFEDisplacementMapElement::Filter(ns
       PRUint32 targIndex = y * stride + 4 * x;
       // At some point we might want to replace this with a bilinear sample.
       PRInt32 sourceX = x +
         NSToIntFloor(scaleOver255 * displacementData[targIndex + xChannel] +
                 scaleAdjustment);
       PRInt32 sourceY = y +
         NSToIntFloor(scaleOver255 * displacementData[targIndex + yChannel] +
                 scaleAdjustment);
-      if (sourceX < 0 || sourceX >= width ||
-          sourceY < 0 || sourceY >= height) {
-        *(PRUint32*)(targetData + targIndex) = 0;
+
+      bool outOfBounds = sourceX < 0 || sourceX >= width ||
+                         sourceY < 0 || sourceY >= height;
+      PRUint8* data;
+      PRInt32 multiplier;
+      if (outOfBounds) {
+        data = dummyData;
+        multiplier = 0;
       } else {
-        *(PRUint32*)(targetData + targIndex) =
-          *(PRUint32*)(sourceData + sourceY * stride + 4 * sourceX);
+        data = sourceData;
+        multiplier = 1;
       }
+      *(PRUint32*)(targetData + targIndex) =
+        *(PRUint32*)(data + multiplier * (sourceY * stride + 4 * sourceX));
     }
   }
   return NS_OK;
 }
 
 bool
 nsSVGFEDisplacementMapElement::AttributeAffectsRendering(PRInt32 aNameSpaceID,
                                                          nsIAtom* aAttribute) const
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -197,17 +197,16 @@ nsSVGSVGElement::nsSVGSVGElement(already
   : nsSVGSVGElementBase(aNodeInfo),
     mCoordCtx(nsnull),
     mViewportWidth(0),
     mViewportHeight(0),
     mCurrentTranslate(0.0f, 0.0f),
     mCurrentScale(1.0f),
     mPreviousTranslate(0.0f, 0.0f),
     mPreviousScale(1.0f),
-    mRedrawSuspendCount(0),
     mStartAnimationOnBindToTree(!aFromParser),
     mImageNeedsTransformInvalidation(false),
     mIsPaintingSVGImageElement(false)
 {
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
@@ -374,63 +373,35 @@ nsSVGSVGElement::GetCurrentTranslate(nsI
 {
   return mCurrentTranslate.ToDOMVal(this, aCurrentTranslate);
 }
 
 /* unsigned long suspendRedraw (in unsigned long max_wait_milliseconds); */
 NS_IMETHODIMP
 nsSVGSVGElement::SuspendRedraw(PRUint32 max_wait_milliseconds, PRUint32 *_retval)
 {
+  // suspendRedraw is a no-op in Mozilla, so it doesn't matter what
+  // we set the ID out-param to:
   *_retval = 1;
-
-  if (++mRedrawSuspendCount > 1) 
-    return NS_OK;
-
-  nsIFrame* frame = GetPrimaryFrame();
-  if (frame) {
-    nsISVGSVGFrame* svgframe = do_QueryFrame(frame);
-    // might fail this check if we've failed conditional processing
-    if (svgframe) {
-      svgframe->SuspendRedraw();
-    }
-  }
-  
   return NS_OK;
 }
 
 /* void unsuspendRedraw (in unsigned long suspend_handle_id); */
 NS_IMETHODIMP
 nsSVGSVGElement::UnsuspendRedraw(PRUint32 suspend_handle_id)
 {
-  if (mRedrawSuspendCount == 0) {
-    return NS_ERROR_FAILURE;
-  }
-                 
-  if (mRedrawSuspendCount > 1) {
-    --mRedrawSuspendCount;
-    return NS_OK;
-  }
-  
-  return UnsuspendRedrawAll();
+  // no-op
+  return NS_OK;
 }
 
 /* void unsuspendRedrawAll (); */
 NS_IMETHODIMP
 nsSVGSVGElement::UnsuspendRedrawAll()
 {
-  mRedrawSuspendCount = 0;
-
-  nsIFrame* frame = GetPrimaryFrame();
-  if (frame) {
-    nsISVGSVGFrame* svgframe = do_QueryFrame(frame);
-    // might fail this check if we've failed conditional processing
-    if (svgframe) {
-      svgframe->UnsuspendRedraw();
-    }
-  }  
+  // no-op
   return NS_OK;
 }
 
 /* void forceRedraw (); */
 NS_IMETHODIMP
 nsSVGSVGElement::ForceRedraw()
 {
   nsIDocument* doc = GetCurrentDoc();
--- a/content/svg/content/src/nsSVGSwitchElement.cpp
+++ b/content/svg/content/src/nsSVGSwitchElement.cpp
@@ -82,28 +82,32 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGSwi
 nsSVGSwitchElement::nsSVGSwitchElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsSVGSwitchElementBase(aNodeInfo)
 {
 }
 
 void
 nsSVGSwitchElement::MaybeInvalidate()
 {
-  // We don't reuse UpdateActiveChild() and check if mActiveChild has changed
-  // to determine if we should invalidate. If we did that,
-  // nsSVGUtils::UpdateGraphic would not invalidate the old mActiveChild area!
+  // We must not change mActiveChild until after
+  // InvalidateAndScheduleBoundsUpdate has been called, otherwise
+  // it will not correctly invalidate the old mActiveChild area.
 
-  if (FindActiveChild() == mActiveChild) {
+  nsIContent *newActiveChild = FindActiveChild();
+
+  if (newActiveChild == mActiveChild) {
     return;
   }
 
   nsIFrame *frame = GetPrimaryFrame();
   if (frame) {
-    nsSVGUtils::UpdateGraphic(frame);
+    nsSVGUtils::InvalidateAndScheduleBoundsUpdate(frame);
   }
+
+  mActiveChild = newActiveChild;
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGSwitchElement)
 
--- a/dom/base/DOMRequestHelper.jsm
+++ b/dom/base/DOMRequestHelper.jsm
@@ -38,16 +38,24 @@ DOMRequestIpcHelper.prototype = {
       return this._requests[aId];
   },
 
   removeRequest: function(aId) {
     if (this._requests[aId])
       delete this._requests[aId];
   },
 
+  takeRequest: function(aId) {
+    if (!this._requests[aId])
+      return null;
+    let request = this._requests[aId];
+    delete this._requests[aId];
+    return request;
+  },
+
   _getRandomId: function() {
     return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
   },
 
   observe: function(aSubject, aTopic, aData) {
     let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
     if (wId == this.innerWindowID) {
       Services.obs.removeObserver(this, "inner-window-destroyed");
--- a/dom/base/ScreenOrientation.h
+++ b/dom/base/ScreenOrientation.h
@@ -3,16 +3,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ScreenOrientation_h
 #define mozilla_dom_ScreenOrientation_h
 
 namespace mozilla {
 namespace dom {
 
+// Make sure that any change here is also made in
+// * mobile/android/base/GeckoScreenOrientationListener.java
+// * embedding/android/GeckoScreenOrientationListener.java
 enum ScreenOrientation {
   eScreenOrientation_Current            = 0,
   eScreenOrientation_PortraitPrimary    = 1,  // 00000001
   eScreenOrientation_PortraitSecondary  = 2,  // 00000010
   eScreenOrientation_Portrait           = 3,  // 00000011
   eScreenOrientation_LandscapePrimary   = 4,  // 00000100
   eScreenOrientation_LandscapeSecondary = 8,  // 00001000
   eScreenOrientation_Landscape          = 12, // 00001100
--- a/dom/interfaces/events/nsIDOMDataTransfer.idl
+++ b/dom/interfaces/events/nsIDOMDataTransfer.idl
@@ -35,17 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIVariant;
 interface nsIDOMFileList;
 
-[scriptable, uuid(E929ACB6-435C-4CB8-9AD1-AE3B9353BCC5)]
+[scriptable, uuid(7D73CFBF-EC30-4F8E-B6A4-BB31EB943580)]
 interface nsIDOMDataTransfer : nsISupports
 {
   /**
    * The actual effect that will be used, and should always be one of the
    * possible values of effectAllowed.
    *
    * For dragstart, drag and dragleave events, the dropEffect is initialized
    * to none. Any value assigned to the dropEffect will be set, but the value
@@ -259,13 +259,16 @@ interface nsIDOMDataTransfer : nsISuppor
   /*
    * Integer version of effectAllowed, set to one or a combination of the
    * constants in nsIDragService.
    */
   [noscript] attribute unsigned long effectAllowedInt;
 
   /**
    * Creates a copy of the data transfer object, for the given event type and
-   * user cancelled flag.
+   * user cancelled flag. If isCrossDomainSubFrameDrop is set, then this is a
+   * cross-domain drop from a subframe where access to the data should be
+   * prevented.
    */
   [noscript] nsIDOMDataTransfer clone(in PRUint32 aEventType,
-                                      in boolean aUserCancelled);
+                                      in boolean aUserCancelled,
+                                      in boolean isCrossDomainSubFrameDrop);
 };
--- a/dom/plugins/test/mochitest/cocoa_focus.html
+++ b/dom/plugins/test/mochitest/cocoa_focus.html
@@ -28,18 +28,18 @@
       var plugin1X = (window.mozInnerScreenX + plugin1Bounds.left + 10) * utils.screenPixelsPerCSSPixel;
       var plugin1Y = (window.mozInnerScreenY + plugin1Bounds.top + 10) * utils.screenPixelsPerCSSPixel;
       var plugin2X = (window.mozInnerScreenX + plugin2Bounds.left + 10) * utils.screenPixelsPerCSSPixel;
       var plugin2Y = (window.mozInnerScreenY + plugin2Bounds.top + 10) * utils.screenPixelsPerCSSPixel;
 
       const NSLeftMouseDown          = 1,
             NSLeftMouseUp            = 2;
 
-      // Don't run any tests if we're not testing the Cocoa event model.
       if (plugin1.getEventModel() != 1) {
+        window.opener.todo(false, "Skipping this test when not testing the Cocoa event model");
         window.opener.testsFinished();
         return;
       }
 
       // Initialize to 0 since there is no initial state event,
       // plugins should assume they do not initially have focus.
       var expectedEventCount = 0;
 
--- a/dom/plugins/test/mochitest/cocoa_window_focus.html
+++ b/dom/plugins/test/mochitest/cocoa_window_focus.html
@@ -21,18 +21,18 @@
     function waitForFocus(aCb, aTarget, aBlank) {
       window.opener.SimpleTest.waitForFocus(aCb, aTarget, aBlank);
     }
 
     function runTests() {
       var plugin1 = document.getElementById("plugin1");
       var plugin2 = document.getElementById("plugin2");
 
-      // Don't run any tests if we're not testing the Cocoa event model.
       if (plugin1.getEventModel() != 1) {
+        window.opener.todo(false, "Skipping this test when not testing the Cocoa event model");
         window.opener.testsFinished();
         return;
       }
 
       // The first plugin will have in-page focus for these tests.
       plugin1.focus();
 
       // The expected event count which applies to all instances.
--- a/dom/plugins/test/mochitest/test_pluginstream_seek_close.html
+++ b/dom/plugins/test/mochitest/test_pluginstream_seek_close.html
@@ -1,16 +1,16 @@
 <body>
 <head>
   <title>NPAPI Seekable NPStream Test</title>
   <script type="text/javascript" 
           src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" 
         href="/tests/SimpleTest/test.css" />
-<script type="application/javascript>
+<script>
   SimpleTest.waitForExplicitFinish();
 
   function frameLoaded() {
     var testframe = document.getElementById('testframe');
     var content = testframe.contentDocument.body.innerHTML;
     if (!content.length)
       return;
 
--- a/dom/sms/src/ril/SmsDatabaseService.js
+++ b/dom/sms/src/ril/SmsDatabaseService.js
@@ -313,25 +313,25 @@ SmsDatabaseService.prototype = {
 
   /**
    * nsISmsDatabaseService API
    */
 
   saveReceivedMessage: function saveReceivedMessage(sender, body, date) {
     let message = {delivery:  DELIVERY_RECEIVED,
                    sender:    sender,
-                   receiver:  null,  //TODO see bug 733266
+                   receiver:  this.mRIL.radioState.msisdn, 
                    body:      body,
                    timestamp: date};
     return this.saveMessage(message);
   },
 
   saveSentMessage: function saveSentMessage(receiver, body, date) {
     let message = {delivery:  DELIVERY_SENT,
-                   sender:    null, //TODO see bug 733266
+                   sender:    this.mRIL.radioState.msisdn,
                    receiver:  receiver,
                    body:      body,
                    timestamp: date};
     return this.saveMessage(message);
   },
 
   getMessage: function getMessage(messageId, requestId) {
     if (DEBUG) debug("Retrieving message with ID " + messageId);
@@ -598,13 +598,19 @@ SmsDatabaseService.prototype = {
 
   clearMessageList: function clearMessageList(listId) {
     if (DEBUG) debug("Clearing message list: " + listId);
     delete this.messageLists[listId];
   }
 
 };
 
+XPCOMUtils.defineLazyGetter(SmsDatabaseService.prototype, "mRIL", function () {
+    return Cc["@mozilla.org/telephony/system-worker-manager;1"]
+              .getService(Ci.nsIInterfaceRequestor)
+              .getInterface(Ci.nsIRadioInterfaceLayer);
+});
+
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([SmsDatabaseService]);
 
 function debug() {
   dump("SmsDatabaseService: " + Array.slice(arguments).join(" ") + "\n");
 }
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -145,16 +145,17 @@ function RadioInterfaceLayer() {
     radioState:     null,
     cardState:      null,
     connected:      null,
     roaming:        null,
     signalStrength: null,
     bars:           null,
     operator:       null,
     type:           null,
+    msisdn:         null,
   };
 }
 RadioInterfaceLayer.prototype = {
 
   classID:   RADIOINTERFACELAYER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
                                     classDescription: "RadioInterfaceLayer",
                                     interfaces: [Ci.nsIWorkerHolder,
@@ -273,16 +274,19 @@ RadioInterfaceLayer.prototype = {
         // so an offset can be added if/when the time is actually set.
         if (DEBUG) {
           debug("nitzTime networkTime=" + message.networkTimeInSeconds
                + " timezone=" + message.networkTimeZoneInMinutes
                + " dst=" + message.dstFlag
                + " timestamp=" + message.localTimeStampInMS);
         }
         break;
+      case "siminfo":
+        this.radioState.msisdn = message.msisdn;
+        break;
       default:
         throw new Error("Don't know about this message type: " + message.type);
     }
   },
 
   _isDataEnabled: function _isDataEnabled() {
     try {
       return Services.prefs.getBoolPref("ril.data.enabled");
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -249,16 +249,21 @@ SystemWorkerManager::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mShutdown = true;
 
   StopRil();
 
   mRILWorker = nsnull;
+  nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
+  if (wifi) {
+    wifi->Shutdown();
+    wifi = nsnull;
+  }
   mWifiWorker = nsnull;
 
   nsCOMPtr<nsIObserverService> obs =
     do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   if (obs) {
     obs->RemoveObserver(this, WORKERS_SHUTDOWN_TOPIC);
   }
 }
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1263,17 +1263,18 @@ let RIL = {
         };
         this.iccIO(options);
         break;
 
       case ICC_COMMAND_READ_RECORD:
         // Ignore 2 bytes prefix, which is 4 chars
         let number = GsmPDUHelper.readStringAsBCD().toString().substr(4); 
         if (DEBUG) debug("MSISDN: " + number);
-        this.MSISDN = number;
+        this.MSISDN = number || null;
+        this.sendDOMMessage({type: "siminfo", msisdn: this.MSISDN});
         break;
     } 
   },
 
   _processRegistrationState: function _processRegistrationState(state) {
     let rs = this.registrationState;
     let stateChanged = false;
 
--- a/dom/tests/mochitest/chrome/sizemode_attribute.xul
+++ b/dom/tests/mochitest/chrome/sizemode_attribute.xul
@@ -5,16 +5,17 @@
   Test for fullscreen sizemode in chrome
   -->
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         persist="sizemode"
         sizemode="normal"
         onload="nextStep()">
 
 <script type="text/javascript;version=1.8">
+let testNum = 0;
 let tests = [
   function test1() {
     checkAndContinue("normal");
   },
 
   function test2() {
     listen("fullscreen", function() checkAndContinue("fullscreen"));
     window.fullScreen = true;
@@ -46,16 +47,17 @@ let tests = [
   },
 
   function test8() {
     window.opener.wrappedJSObject.done();
   }
 ];
 
 function nextStep() {
+  testNum++;
   tests.shift()();
 }
 
 function listen(event, fn) {
   window.addEventListener(event, function listener() {
     window.removeEventListener(event, listener, false);
     fn();
   }, false);
@@ -65,19 +67,26 @@ function checkAndContinue(sizemode) {
 
   let windowStates = {
     "fullscreen": window.STATE_FULLSCREEN,
     "normal": window.STATE_NORMAL,
     "maximized": window.STATE_MAXIMIZED
   };
 
   setTimeout(function() {
-    is(window.document.documentElement.getAttribute("sizemode"), sizemode, "sizemode attribute should match actual window state");
-    is(window.fullScreen, sizemode == "fullscreen", "window.fullScreen should match actual window state");
-    is(window.windowState, windowStates[sizemode], "window.sizeMode should match actual window state");
+    // The sizemode attribute is wrong when the window is in fullscreen.
+    // cf. bug 714911
+    if (sizemode != "fullscreen") {
+      is(window.document.documentElement.getAttribute("sizemode"), sizemode,
+         "Test " + testNum + ": sizemode attribute should match actual window state");
+    }
+    is(window.fullScreen, sizemode == "fullscreen",
+       "Test " + testNum + ": window.fullScreen should match actual window state");
+    is(window.windowState, windowStates[sizemode],
+       "Test " + testNum + ": window.sizeMode should match actual window state");
     nextStep();
   }, 0);
 }
 
 let is = window.opener.wrappedJSObject.is;
 
 </script>
 
--- a/dom/tests/mochitest/dom-level1-core/DOMTestCase.js
+++ b/dom/tests/mochitest/dom-level1-core/DOMTestCase.js
@@ -156,23 +156,34 @@ function assertEquals(descr, expected, a
     is(actual.length, expected.length, descr);
   }
 
   function assertInstanceOf(descr, type, obj) {
     if(type == "Attr") {
         is(2, obj.nodeType, descr);
         var specd = obj.specified;
     }
+/*
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_is(type, "Attr", "[DOMTestCase.assertInstanceOf()] Fake default check.");
+    }
+*/
   }
 
   function assertSame(descr, expected, actual) {
     if(expected != actual) {
         is(expected.nodeType, actual.nodeType, descr);
         is(expected.nodeValue, actual.nodeValue, descr);
     }
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(expected, actual, "[DOMTestCase.assertSame()] Fake default check." +
+                                   " (Type=" + actual.nodeType + ", Value=" + actual.nodeValue + ")");
+    }
   }
 
   function assertURIEquals(assertID, scheme, path, host, file, name, query, fragment, isAbsolute, actual) {
     //
     //  URI must be non-null
     ok(assertID && actual);
 
     var uri = actual;
--- a/dom/tests/mochitest/dom-level1-core/test_hc_entitiesremovenameditem1.html
+++ b/dom/tests/mochitest/dom-level1-core/test_hc_entitiesremovenameditem1.html
@@ -122,16 +122,20 @@ entities = docType.entities;
         }
 		catch(ex) {
       success = (typeof(ex.code) != 'undefined' && ex.code == 7);
 		}
 		assertTrue("throw_NO_MODIFICATION_ALLOWED_ERR",success);
 	}
 
 	}
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(builder.contentType, "text/html", "Fake default check");
+    }
 	
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level1/core/hc_entitiesremovenameditem1</h2>
 <p></p>
--- a/dom/tests/mochitest/dom-level1-core/test_hc_entitiessetnameditem1.html
+++ b/dom/tests/mochitest/dom-level1-core/test_hc_entitiessetnameditem1.html
@@ -133,16 +133,20 @@ elem = doc.createElement("br");
           throw ex;
           }
        } else { 
        throw ex;
         }
          }
         
 	}
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(builder.contentType, "text/html", "Fake default check");
+    }
 	
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level1/core/hc_entitiessetnameditem1</h2>
 <p></p>
--- a/dom/tests/mochitest/dom-level1-core/test_hc_nodevalue07.html
+++ b/dom/tests/mochitest/dom-level1-core/test_hc_nodevalue07.html
@@ -123,16 +123,20 @@ newValue = newNode.nodeValue;
       assertNull("initiallyNull",newValue);
     newNode.nodeValue = "This should have no effect";
 
       newValue = newNode.nodeValue;
 
       assertNull("nullAfterAttemptedChange",newValue);
     
 	}
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(builder.contentType, "text/html", "Fake default check");
+    }
 	
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level1/core/hc_nodevalue07</h2>
 <p></p>
--- a/dom/tests/mochitest/dom-level1-core/test_hc_nodevalue08.html
+++ b/dom/tests/mochitest/dom-level1-core/test_hc_nodevalue08.html
@@ -123,16 +123,20 @@ newValue = newNode.nodeValue;
       assertNull("initiallyNull",newValue);
     newNode.nodeValue = "This should have no effect";
 
       newValue = newNode.nodeValue;
 
       assertNull("nullAfterAttemptedChange",newValue);
     
 	}
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(builder.contentType, "text/html", "Fake default check");
+    }
 	
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level1/core/hc_nodevalue08</h2>
 <p></p>
--- a/dom/tests/mochitest/dom-level1-core/test_hc_notationsremovenameditem1.html
+++ b/dom/tests/mochitest/dom-level1-core/test_hc_notationsremovenameditem1.html
@@ -122,16 +122,20 @@ notations = docType.notations;
         }
 		catch(ex) {
       success = (typeof(ex.code) != 'undefined' && ex.code == 7);
 		}
 		assertTrue("throw_NO_MODIFICATION_ALLOWED_ERR",success);
 	}
 
 	}
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(builder.contentType, "text/html", "Fake default check");
+    }
 	
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level1/core/hc_notationsremovenameditem1</h2>
 <p></p>
--- a/dom/tests/mochitest/dom-level1-core/test_hc_notationssetnameditem1.html
+++ b/dom/tests/mochitest/dom-level1-core/test_hc_notationssetnameditem1.html
@@ -133,16 +133,20 @@ elem = doc.createElement("br");
           throw ex;
           }
        } else { 
        throw ex;
         }
          }
         
 	}
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(builder.contentType, "text/html", "Fake default check");
+    }
 	
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level1/core/hc_notationssetnameditem1</h2>
 <p></p>
--- a/dom/tests/mochitest/dom-level1-core/test_nodelistindexequalzero.html
+++ b/dom/tests/mochitest/dom-level1-core/test_nodelistindexequalzero.html
@@ -112,16 +112,20 @@ function nodelistindexequalzero() {
 
       
 	if(
 	!("#text" == childName)
 	) {
 	assertEquals("childName","employeeId",childName);
        
 	}
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(childName, "#text", "Fake default check");
+    }
 	
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level1/core/nodelistindexequalzero</h2>
 <p></p>
--- a/dom/tests/mochitest/dom-level2-core/DOMTestCase.js
+++ b/dom/tests/mochitest/dom-level2-core/DOMTestCase.js
@@ -156,23 +156,36 @@ function assertEquals(descr, expected, a
     is(actual.length, expected.length, descr);
   }
 
   function assertInstanceOf(descr, type, obj) {
     if(type == "Attr") {
         is(2, obj.nodeType, descr);
         var specd = obj.specified;
     }
+/*
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_is(type, "Attr", "[DOMTestCase.assertInstanceOf()] Fake default check.");
+    }
+*/
   }
 
   function assertSame(descr, expected, actual) {
     if(expected != actual) {
         is(expected.nodeType, actual.nodeType, descr);
         is(expected.nodeValue, actual.nodeValue, descr);
     }
+/*
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(expected, actual, "[DOMTestCase.assertSame()] Fake default check." +
+                                   " (Type=" + actual.nodeType + ", Value=" + actual.nodeValue + ")");
+    }
+*/
   }
 
   function assertURIEquals(assertID, scheme, path, host, file, name, query, fragment, isAbsolute, actual) {
     //
     //  URI must be non-null
     ok(assertID && actual);
 
     var uri = actual;
--- a/dom/tests/mochitest/dom-level2-core/test_createDocument03.html
+++ b/dom/tests/mochitest/dom-level2-core/test_createDocument03.html
@@ -113,16 +113,18 @@ function createDocument03() {
 		try {
             aNewDoc = domImpl.createDocument(namespaceURI,qualifiedName,docType);
             success = true;
         }
 		catch(ex) {
       success = false;
 		}
 		//assertTrue("no_throw_WRONG_DOCUMENT_ERR",success);
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      ok(success, "createDocument() succeeded");
 	}
 
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level2/core/createDocument03</h2>
--- a/dom/tests/mochitest/dom-level2-html/DOMTestCase.js
+++ b/dom/tests/mochitest/dom-level2-html/DOMTestCase.js
@@ -156,23 +156,36 @@ function assertEquals(descr, expected, a
     is(actual.length, expected.length, descr);
   }
 
   function assertInstanceOf(descr, type, obj) {
     if(type == "Attr") {
         is(2, obj.nodeType, descr);
         var specd = obj.specified;
     }
+/*
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_is(type, "Attr", "[DOMTestCase.assertInstanceOf()] Fake default check.");
+    }
+*/
   }
 
   function assertSame(descr, expected, actual) {
     if(expected != actual) {
         is(expected.nodeType, actual.nodeType, descr);
         is(expected.nodeValue, actual.nodeValue, descr);
     }
+/*
+    else {
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      todo_isnot(expected, actual, "[DOMTestCase.assertSame()] Fake default check." +
+                                   " (Type=" + actual.nodeType + ", Value=" + actual.nodeValue + ")");
+    }
+*/
   }
 
   function assertURIEquals(assertID, scheme, path, host, file, name, query, fragment, isAbsolute, actual) {
     //
     //  URI must be non-null
     ok(assertID && actual);
 
     var uri = actual;
--- a/dom/tests/mochitest/dom-level2-html/test_HTMLDocument18.html
+++ b/dom/tests/mochitest/dom-level2-html/test_HTMLDocument18.html
@@ -83,16 +83,18 @@ function HTMLDocument18() {
       
       var docRef = null;
       if (typeof(this.doc) != 'undefined') {
         docRef = this.doc;
       }
       doc = load(docRef, "doc", "document");
       doc.close();
       
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      ok(true, "Test complete");
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLDocument18</h2>
 <p>&lt;test name='HTMLDocument18' schemaLocation='http://www.w3.org/2001/DOM-Test-Suite/Level-1 dom1.xsd'&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;metadata&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;HTMLDocument18&lt;/title&gt;
 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;creator&gt;Curt Arnold&lt;/creator&gt;
--- a/dom/tests/mochitest/dom-level2-html/test_HTMLDocument19.html
+++ b/dom/tests/mochitest/dom-level2-html/test_HTMLDocument19.html
@@ -110,16 +110,18 @@ function HTMLDocument19() {
       doc.write("&lt;/body>");
       doc.write("&lt;p>");
       doc.write("Hello, World.");
       doc.write("&lt;/p>");
       doc.write("&lt;/body>");
       doc.write("&lt;/html>");
       doc.close();
       
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      ok(true, "Test complete");
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLDocument19</h2>
 <p>&lt;test name='HTMLDocument19' schemaLocation='http://www.w3.org/2001/DOM-Test-Suite/Level-1 dom1.xsd'&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;metadata&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;HTMLDocument19&lt;/title&gt;
 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;creator&gt;Curt Arnold&lt;/creator&gt;
--- a/dom/tests/mochitest/dom-level2-html/test_HTMLDocument20.html
+++ b/dom/tests/mochitest/dom-level2-html/test_HTMLDocument20.html
@@ -110,16 +110,18 @@ function HTMLDocument20() {
       doc.writeln("&lt;/body>");
       doc.writeln("&lt;p>");
       doc.writeln("Hello, World.");
       doc.writeln("&lt;/p>");
       doc.writeln("&lt;/body>");
       doc.writeln("&lt;/html>");
       doc.close();
       
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      ok(true, "Test complete");
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLDocument20</h2>
 <p>&lt;test name='HTMLDocument20' schemaLocation='http://www.w3.org/2001/DOM-Test-Suite/Level-1 dom1.xsd'&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;metadata&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;HTMLDocument20&lt;/title&gt;
 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;creator&gt;Curt Arnold&lt;/creator&gt;
--- a/dom/tests/mochitest/dom-level2-html/test_HTMLDocument21.html
+++ b/dom/tests/mochitest/dom-level2-html/test_HTMLDocument21.html
@@ -119,16 +119,18 @@ function HTMLDocument21() {
       doc.write("&lt;pre>");
       doc.write("Hello, World.");
       doc.write("Hello, World.");
       doc.writeln("&lt;/pre>");
       doc.writeln("&lt;/body>");
       doc.writeln("&lt;/html>");
       doc.close();
       
+      // Ensure at least one SimpleTest check is reported. (Bug 483992)
+      ok(true, "Test complete");
 }
 
 </script>
 </head>
 <body>
 <h2>Test http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLDocument21</h2>
 <p>&lt;test name='HTMLDocument21' schemaLocation='http://www.w3.org/2001/DOM-Test-Suite/Level-1 dom1.xsd'&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;metadata&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;HTMLDocument21&lt;/title&gt;
 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;creator&gt;Curt Arnold&lt;/creator&gt;
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -5,26 +5,29 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
 const DEBUG = true; // set to false to suppress debug messages
 
 const DOMWIFIMANAGER_CONTRACTID = "@mozilla.org/wifimanager;1";
 const DOMWIFIMANAGER_CID        = Components.ID("{2cf775a7-1837-410c-9e26-323c42e076da}");
 
 function DOMWifiManager() {
 }
 
 DOMWifiManager.prototype = {
+  __proto__: DOMRequestIpcHelper.prototype,
+
   classID:   DOMWIFIMANAGER_CID,
   classInfo: XPCOMUtils.generateCI({classID: DOMWIFIMANAGER_CID,
                                     contractID: DOMWIFIMANAGER_CONTRACTID,
                                     classDescription: "DOMWifiManager",
                                     interfaces: [Ci.nsIDOMWifiManager],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMWifiManager,
@@ -37,121 +40,90 @@ DOMWifiManager.prototype = {
 
     let perm = (principal == secMan.getSystemPrincipal()) ?
                  Ci.nsIPermissionManager.ALLOW_ACTION :
                  Services.perms.testExactPermission(principal.URI, "wifi-manage");
 
     // Only pages with perm set can use the wifi manager.
     this._hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
 
-    this._window = aWindow;
-
     // Maintain this state for synchronous APIs.
     this._currentNetwork = null;
     this._enabled = true;
 
-    Services.obs.addObserver(this, "inner-window-destroyed", false);
-    let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-    this.innerWindowID = util.currentInnerWindowID;
-
-    this._messages = ["WifiManager:setEnabled:Return:OK", "WifiManager:setEnabled:Return:NO",
+    const messages = ["WifiManager:setEnabled:Return:OK", "WifiManager:setEnabled:Return:NO",
                       "WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO",
                       "WifiManager:associate:Return:OK", "WifiManager:associate:Return:NO",
-                      "WifiManager:onassociate", "WifiManager:onconnect", "WifiManager:ondisconnect"];
+                      "WifiManager:onconnecting", "WifiManager:onassociate",
+                      "WifiManager:onconnect", "WifiManager:ondisconnect"];
+    this.initHelper(aWindow, messages);
     this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
 
-    this._messages.forEach((function(msgName) {
-      this._mm.addMessageListener(msgName, this);
-    }).bind(this));
-
-    this._id = this._getRandomId();
-    this._requests = Object.create(null);
-
     var state = this._mm.sendSyncMessage("WifiManager:getState");
     this._currentNetwork = state[0].network;
     this._enabled = state[0].enabled;
   },
 
-  observe: function(aSubject, aTopic, aData) {
-    if (aTopic !== "inner-window-destroyed")
-      throw "Unexpected topic";
-
-    let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
-    if (wId == this.innerWindowID) {
-      this._messages.forEach((function(msgName) {
-        this._mm.removeMessageListener(msgName, this);
-      }).bind(this));
-
-      Services.obs.removeObserver(this, "inner-window-destroyed");
-      this._window = null;
-      this._onAssociate = null;
-      this._onConnect = null;
-      this._onDisconnect = null;
-    }
-  },
-
-  _getRandomId: function() {
-    return Cc["@mozilla.org/uuid-generator;1"]
-             .getService(Ci.nsIUUIDGenerator)
-             .generateUUID()
-             .toString();
-  },
-
-  _takeRequest: function(id) {
-    let request = this._requests[id];
-    delete this._requests[id];
-    return request;
+  uninit: function() {
+    this._onConnecting = null;
+    this._onAssociate = null;
+    this._onConnect = null;
+    this._onDisconnect = null;
   },
 
   _sendMessageForRequest: function(name, data, request) {
-    let id = this._getRandomId();
-    this._requests[id] = request;
+    let id = this.getRequestId(request);
     this._mm.sendAsyncMessage(name, { data: data, rid: id, mid: this._id });
   },
 
   receiveMessage: function(aMessage) {
     let msg = aMessage.json;
     if (msg.mid && msg.mid != this._id)
       return;
 
     let request;
     switch (aMessage.name) {
       case "WifiManager:setEnabled:Return:OK":
-        request = this._takeRequest(msg.rid);
+        request = this.takeRequest(msg.rid);
         this._enabled = msg.data;
         if (!this._enabled)
           this._currentNetwork = null;
         Services.DOMRequest.fireSuccess(request, true);
         break;
 
       case "WifiManager:setEnabled:Return:NO":
-        request = this._takeRequest(msg.rid);
+        request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, "Unable to initialize wifi");
         break;
 
       case "WifiManager:getNetworks:Return:OK":
-        request = this._takeRequest(msg.rid);
+        request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:getNetworks:Return:NO":
-        request = this._takeRequest(msg.rid);
+        request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, "Unable to scan for networks");
         break;
 
       case "WifiManager:associate:Return:OK":
-        request = this._takeRequest(msg.rid);
+        request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireSuccess(request, true);
         break;
 
       case "WifiManager:associate:Return:NO":
-        request = this._takeRequest(msg.rid);
+        request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, "Unable to add the network");
         break;
 
+      case "WifiManager:onconnecting":
+        this._currentNetwork = msg.network;
+        this._fireOnConnecting(msg.network);
+        break;
+
       case "WifiManager:onassociate":
         this._currentNetwork = msg.network;
         this._fireOnAssociate(msg.network);
         break;
 
       case "WifiManager:onconnect":
         this._currentNetwork = msg.network;
         this._fireOnConnect(msg.network);
@@ -159,16 +131,21 @@ DOMWifiManager.prototype = {
 
       case "WifiManager:ondisconnect":
         this._fireOnDisconnect(this._currentNetwork);
         this._currentNetwork = null;
         break;
     }
   },
 
+  _fireOnConnecting: function onConnecting(network) {
+    if (this._onConnecting)
+      this._onConnecting.handleEvent(new WifiStateChangeEvent(network));
+  },
+
   _fireOnAssociate: function onAssociate(network) {
     if (this._onAssociate)
       this._onAssociate.handleEvent(new WifiStateChangeEvent(network));
   },
 
   _fireOnConnect: function onConnect(network) {
     if (this._onConnect)
       this._onConnect.handleEvent(new WifiStateChangeEvent(network));
@@ -179,49 +156,55 @@ DOMWifiManager.prototype = {
       this._onDisconnect.handleEvent(new WifiStateChangeEvent(network));
     }
   },
 
   // nsIDOMWifiManager
   setEnabled: function nsIDOMWifiManager_setEnabled(enabled) {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    var request = Services.DOMRequest.createRequest(this._window);
+    var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:setEnabled", enabled, request);
     return request;
   },
 
   getNetworks: function nsIDOMWifiManager_getNetworks() {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    var request = Services.DOMRequest.createRequest(this._window);
+    var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:getNetworks", null, request);
     return request;
   },
 
   associate: function nsIDOMWifiManager_associate(network) {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    var request = Services.DOMRequest.createRequest(this._window);
+    var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:associate", network, request);
     return request;
   },
 
   get enabled() {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._enabled;
   },
 
   get connectedNetwork() {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._currentNetwork;
   },
 
+  set onconnecting(callback) {
+    if (!this._hasPrivileges)
+      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+    this._onConnecting = callback;
+  },
+
   set onassociate(callback) {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     this._onAssociate = callback;
   },
 
   set onconnect(callback) {
     if (!this._hasPrivileges)
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1217,16 +1217,17 @@ function WifiWorker() {
       // need to detect if we're looping in this state and bail out.
       WifiManager.reconnect(function(){});
     } else if (this.state === "ASSOCIATING") {
       // id has not yet been filled in, so we can only report the ssid and
       // bssid.
       self.currentNetwork =
         { bssid: WifiManager.connectionInfo.bssid,
           ssid: quote(WifiManager.connectionInfo.ssid) };
+      self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) });
     } else if (this.state === "ASSOCIATED") {
       self.currentNetwork.netId = this.id;
       WifiManager.getNetworkConfiguration(self.currentNetwork, function (){});
     } else if (this.state === "COMPLETED") {
       // Now that we've successfully completed the connection, re-enable the
       // rest of our networks.
       // XXX Need to do this eventually if the user entered an incorrect
       // password. For now, we require user interaction to break the loop and
--- a/dom/wifi/nsIWifi.idl
+++ b/dom/wifi/nsIWifi.idl
@@ -34,18 +34,22 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "nsIDOMDOMRequest.idl"
 #include "nsIDOMEvent.idl"
 
-[scriptable, uuid(9DCE05BF-659C-4427-A050-0EAC3BB6C1C0)]
+[scriptable, uuid(abb936bc-ba81-4c23-8dfa-3e5d96557044)]
 interface nsIWifi : nsISupports {
+    /**
+     * Shutdown the wifi system.
+     */
+    void shutdown();
 };
 
 [scriptable, uuid(1509221f-470e-4445-b476-88e74fd5c617)]
 interface nsIDOMWifiManager : nsISupports {
     /**
      * TODO Remove in favor of a settings API.
      * Activates or disactivates wifi.
      * onsuccess: Wifi has been successfully activated and can start
@@ -83,26 +87,29 @@ interface nsIDOMWifiManager : nsISupport
     readonly attribute boolean enabled;
 
     /**
      * A network object describing the currently connected network.
      */
     readonly attribute jsval connectedNetwork;
 
     /**
-     * These three functions serve as state notification listeners.
+     * These four functions serve as state notification listeners.
+     * onconnecting: Fires when we start the process of connecting to a
+     *               network.
      * onassociate: Fires when we have connected to an access point but do not
      *              yet have an IP address.
      * onconnect: Fires once we are fully connected to an access point and can
      *            access the internet.
      * ondisconnect: Fires when we either fail to connect to an access point
      *               (transition: onassociate -> ondisconnect) or when we were
      *               connected to a network but have disconnected for any
      *               reason (transition: onconnect -> ondisconnect).
      */
+             attribute nsIDOMEventListener onconnecting;
              attribute nsIDOMEventListener onassociate;
              attribute nsIDOMEventListener onconnect;
              attribute nsIDOMEventListener ondisconnect;
 };
 
 [scriptable, uuid(4674c6f1-ea64-44db-ac2f-e7bd6514dfd6)]
 interface nsIDOMWifiStateChangeEvent : nsIDOMEvent {
     /**
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -51,16 +51,17 @@
 #include "nsIDocument.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsISelection.h"
 #include "nsISelectionPrivate.h"
 #include "nsIDOMHTMLAnchorElement.h"
 #include "nsIDOMHTMLImageElement.h"
 #include "nsISelectionController.h"
 #include "nsIFileChannel.h"
+#include "nsIPrivateDOMEvent.h"
 
 #include "nsIDocumentObserver.h"
 #include "nsIDocumentStateListener.h"
 
 #include "nsIEnumerator.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMRange.h"
--- a/editor/libeditor/html/tests/test_bug616590.xul
+++ b/editor/libeditor/html/tests/test_bug616590.xul
@@ -56,16 +56,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP)
       {
         var editor = this.mEditor.getEditor(this.mEditor.contentWindow);
         if (editor) {
           editor.QueryInterface(Components.interfaces.nsIEditorMailSupport);
           editor.insertAsCitedQuotation("<html><body><div contenteditable>foo</div></body></html>", "", true);
           document.documentElement.clientWidth;
           progress.removeProgressListener(this);
+          ok(true, "Test complete");
           SimpleTest.finish();
         }
       }
     },
 
 
     onProgressChange : function(aWebProgress, aRequest,
                                 aCurSelfProgress, aMaxSelfProgress,
--- a/editor/libeditor/text/nsPlaintextDataTransfer.cpp
+++ b/editor/libeditor/text/nsPlaintextDataTransfer.cpp
@@ -45,16 +45,17 @@
 #include "nsIFormControl.h"
 #include "nsIDOMEventTarget.h" 
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMDragEvent.h"
 #include "nsISelection.h"
 #include "nsCRT.h"
 #include "nsServiceManagerUtils.h"
+#include "nsIPrivateDOMEvent.h"
 
 #include "nsIDOMRange.h"
 #include "nsIDOMDOMStringList.h"
 #include "nsIDocumentEncoder.h"
 #include "nsISupportsPrimitives.h"
 
 // Drag & Drop, Clipboard
 #include "nsIClipboard.h"
@@ -187,16 +188,25 @@ nsresult nsPlaintextEditor::InsertFromDr
 
   nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aDropEvent));
   NS_ENSURE_TRUE(dragEvent, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
   nsresult rv = dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+  NS_ASSERTION(dragSession, "No drag session");
+
+  nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aDropEvent));
+  nsDragEvent* dragEventInternal = static_cast<nsDragEvent *>(privateEvent->GetInternalNSEvent());
+  if (nsContentUtils::CheckForSubFrameDrop(dragSession, dragEventInternal)) {
+    return NS_OK;
+  }
+
   // Current doc is destination
   nsCOMPtr<nsIDOMDocument> destdomdoc; 
   rv = GetDocument(getter_AddRefs(destdomdoc)); 
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRUint32 numItems = 0;
   rv = dataTransfer->GetMozItemCount(&numItems);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -507,16 +507,17 @@ abstract public class GeckoApp
         // Whatever we do here should be fast, because we're blocking
         // the next activity from showing up until we finish.
 
         // onPause will be followed by either onResume or onStop.
         super.onPause();
 
         unregisterReceiver(mConnectivityReceiver);
         GeckoNetworkManager.getInstance().stop();
+        GeckoScreenOrientationListener.getInstance().stop();
     }
 
     @Override
     public void onResume()
     {
         Log.i(LOG_FILE_NAME, "resume");
         if (checkLaunchState(LaunchState.GeckoRunning))
             GeckoAppShell.onResume();
@@ -526,16 +527,17 @@ abstract public class GeckoApp
 
         // Just in case. Normally we start in onNewIntent
         if (checkLaunchState(LaunchState.PreLaunch) ||
             checkLaunchState(LaunchState.Launching))
             onNewIntent(getIntent());
 
         registerReceiver(mConnectivityReceiver, mConnectivityFilter);
         GeckoNetworkManager.getInstance().start();
+        GeckoScreenOrientationListener.getInstance().start();
     }
 
     @Override
     public void onStop()
     {
         Log.i(LOG_FILE_NAME, "stop");
         // We're about to be stopped, potentially in preparation for
         // being destroyed.  We're killable after this point -- as I
@@ -581,16 +583,17 @@ abstract public class GeckoApp
 
         if (SmsManager.getInstance() != null) {
             SmsManager.getInstance().stop();
             if (isFinishing())
                 SmsManager.getInstance().shutdown();
         }
 
         GeckoNetworkManager.getInstance().stop();
+        GeckoScreenOrientationListener.getInstance().stop();
 
         super.onDestroy();
 
         unregisterReceiver(mBatteryReceiver);
     }
 
     @Override
     public void onConfigurationChanged(android.content.res.Configuration newConfig)
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -1838,9 +1838,21 @@ public class GeckoAppShell
     }
 
     public static void disableNetworkNotifications() {
         GeckoNetworkManager.getInstance().disableNotifications();
     }
 
     // This is only used in Native Fennec.
     public static void setPreventPanning(final boolean aPreventPanning) { }
+
+    public static short getScreenOrientation() {
+        return GeckoScreenOrientationListener.getInstance().getScreenOrientation();
+    }
+
+    public static void enableScreenOrientationNotifications() {
+        GeckoScreenOrientationListener.getInstance().enableNotifications();
+    }
+
+    public static void disableScreenOrientationNotifications() {
+        GeckoScreenOrientationListener.getInstance().disableNotifications();
+    }
 }
--- a/embedding/android/GeckoEvent.java
+++ b/embedding/android/GeckoEvent.java
@@ -75,16 +75,17 @@ public class GeckoEvent {
     public static final int GECKO_EVENT_SYNC = 15;
     public static final int ACTIVITY_START = 17;
     public static final int SAVE_STATE = 18;
     public static final int BROADCAST = 19;
     public static final int VIEWPORT = 20;
     public static final int VISITED = 21;
     public static final int NETWORK_CHANGED = 22;
     public static final int PROXIMITY_EVENT = 23;
+    public static final int SCREENORIENTATION_CHANGED = 26;
 
     public static final int IME_COMPOSITION_END = 0;
     public static final int IME_COMPOSITION_BEGIN = 1;
     public static final int IME_SET_TEXT = 2;
     public static final int IME_GET_TEXT = 3;
     public static final int IME_DELETE_TEXT = 4;
     public static final int IME_SET_SELECTION = 5;
     public static final int IME_GET_SELECTION = 6;
@@ -121,16 +122,18 @@ public class GeckoEvent {
     public int mRangeType, mRangeStyles;
     public int mRangeForeColor, mRangeBackColor;
     public Location mLocation;
     public Address  mAddress;
 
     public double mBandwidth;
     public boolean mCanBeMetered;
 
+    public short mScreenOrientation;
+
     public int mNativeWindow;
 
     public GeckoEvent() {
         mType = NATIVE_POKE;
     }
 
     public GeckoEvent(int evType) {
         mType = evType;
@@ -328,9 +331,14 @@ public class GeckoEvent {
         mCharacters = uri;
     }
 
     public GeckoEvent(double bandwidth, boolean canBeMetered) {
         mType = NETWORK_CHANGED;
         mBandwidth = bandwidth;
         mCanBeMetered = canBeMetered;
     }
+
+    public GeckoEvent(short aScreenOrientation) {
+        mType = SCREENORIENTATION_CHANGED;
+        mScreenOrientation = aScreenOrientation;
+    }
 }
new file mode 100644
--- /dev/null
+++ b/embedding/android/GeckoScreenOrientationListener.java
@@ -0,0 +1,122 @@
+/* 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/. */
+
+package org.mozilla.gecko;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+
+public class GeckoScreenOrientationListener
+{
+  static class OrientationEventListenerImpl extends OrientationEventListener {
+    public OrientationEventListenerImpl(Context c) {
+      super(c);
+    }
+
+    @Override
+    public void onOrientationChanged(int aOrientation) {
+      GeckoScreenOrientationListener.getInstance().updateScreenOrientation();
+    }
+  }
+
+  static private GeckoScreenOrientationListener sInstance = null;
+
+  // Make sure that any change in dom/base/ScreenOrientation.h happens here too.
+  static public final short eScreenOrientation_PortraitPrimary    = 1;
+  static public final short eScreenOrientation_PortraitSecondary  = 2;
+  static public final short eScreenOrientation_LandscapePrimary   = 4;
+  static public final short eScreenOrientation_LandscapeSecondary = 8;
+
+  private short mOrientation;
+  private OrientationEventListenerImpl mListener = null;
+
+  // Whether the listener should be listening to changes.
+  private boolean mShouldBeListening = false;
+  // Whether the listener should notify Gecko that a change happened.
+  private boolean mShouldNotify      = false;
+
+  private GeckoScreenOrientationListener() {
+    mListener = new OrientationEventListenerImpl(GeckoApp.mAppContext);
+  }
+
+  public static GeckoScreenOrientationListener getInstance() {
+    if (sInstance == null) {
+      sInstance = new GeckoScreenOrientationListener();
+    }
+
+    return sInstance;
+  }
+
+  public void start() {
+    mShouldBeListening = true;
+    updateScreenOrientation();
+
+    if (mShouldNotify) {
+      startListening();
+    }
+  }
+
+  public void stop() {
+    mShouldBeListening = false;
+
+    if (mShouldNotify) {
+      stopListening();
+    }
+  }
+
+  public void enableNotifications() {
+    updateScreenOrientation();
+    mShouldNotify = true;
+
+    if (mShouldBeListening) {
+      startListening();
+    }
+  }
+
+  public void disableNotifications() {
+    mShouldNotify = false;
+
+    if (mShouldBeListening) {
+      stopListening();
+    }
+  }
+
+  private void startListening() {
+    mListener.enable();
+  }
+
+  private void stopListening() {
+    mListener.disable();
+  }
+
+  // NOTE: this is public so OrientationEventListenerImpl can access it.
+  // Unfortunately, Java doesn't know about friendship.
+  public void updateScreenOrientation() {
+    int rotation = GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getRotation();
+    short previousOrientation = mOrientation;
+
+    if (rotation == Surface.ROTATION_0) {
+      mOrientation = eScreenOrientation_PortraitPrimary;
+    } else if (rotation == Surface.ROTATION_180) {
+      mOrientation = eScreenOrientation_PortraitSecondary;
+    } else if (rotation == Surface.ROTATION_270) {
+      mOrientation = eScreenOrientation_LandscapeSecondary;
+    } else if (rotation == Surface.ROTATION_90) {
+      mOrientation = eScreenOrientation_LandscapePrimary;
+    } else {
+      Log.e("GeckoScreenOrientationListener", "Unexpected value received! (" + rotation + ")");
+      return;
+    }
+
+    if (mShouldNotify && mOrientation != previousOrientation) {
+      GeckoAppShell.sendEventToGecko(new GeckoEvent(mOrientation));
+    }
+  }
+
+  public short getScreenOrientation() {
+    return mOrientation;
+  }
+}
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -52,16 +52,17 @@ JAVAFILES = \
   GeckoEvent.java \
   GeckoSurfaceView.java \
   GeckoInputConnection.java \
   AlertNotification.java \
   SurfaceInfo.java \
   GeckoBatteryManager.java \
   VideoPlayer.java \
   GeckoNetworkManager.java \
+  GeckoScreenOrientationListener.java \
   $(NULL)
 
 ifdef MOZ_WEBSMS_BACKEND
 JAVAFILES += GeckoSmsManager.java
 endif
 
 PROCESSEDJAVAFILES = \
   App.java \
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -502,17 +502,16 @@ public:
         default:
             return nsnull;
         }
     }
 
     bool SwapBuffers()
     {
         if (mSurface && !mPlatformContext) {
-            //sEGLLibrary.fSetSwapRectangleANDROID(EGL_DISPLAY(), mSurface, 0, 0, gScreenBounds.width, gScreenBounds.height);
             return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
         } else {
             return false;
         }
     }
     // GLContext interface - returns Tiled Texture Image in our case
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -136,19 +136,16 @@ GLLibraryEGL::EnsureInitialized()
         SYMBOL(GetProcAddress),
         SYMBOL(SwapBuffers),
         SYMBOL(CopyBuffers),
         SYMBOL(QueryString),
         SYMBOL(QueryContext),
         SYMBOL(BindTexImage),
         SYMBOL(ReleaseTexImage),
         SYMBOL(QuerySurface),
-#ifdef MOZ_WIDGET_GONK
-        SYMBOL(SetSwapRectangleANDROID),
-#endif
         { NULL, { NULL } }
     };
 
     if (!GLLibraryLoader::LoadSymbols(mEGLLibrary, &earlySymbols[0])) {
         NS_WARNING("Couldn't find required entry points in EGL library (early init)");
         return false;
     }
 
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -318,26 +318,16 @@ public:
     EGLBoolean fDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
     {
         BEFORE_GL_CALL;
         EGLBoolean b = mSymbols.fDestroyImageKHR(dpy, image);
         AFTER_GL_CALL;
         return b;
     }
 
-#ifdef MOZ_WIDGET_GONK
-    EGLBoolean fSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface surface, EGLint left, EGLint top, EGLint width, EGLint height)
-    {
-        BEFORE_GL_CALL;
-        EGLBoolean b = mSymbols.fSetSwapRectangleANDROID(dpy, surface, left, top, width, height);
-        AFTER_GL_CALL;
-        return b;
-    }
-#endif
-
     // New extension which allow us to lock texture and get raw image pointer
     EGLBoolean fLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list)
     {
         BEFORE_GL_CALL;
         EGLBoolean b = mSymbols.fLockSurfaceKHR(dpy, surface, attrib_list);
         AFTER_GL_CALL;
         return b;
     }
@@ -462,20 +452,16 @@ public:
         typedef EGLBoolean (GLAPIENTRY * pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
         pfnBindTexImage fBindTexImage;
         typedef EGLBoolean (GLAPIENTRY * pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer);
         pfnReleaseTexImage fReleaseTexImage;
         typedef EGLImageKHR (GLAPIENTRY * pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
         pfnCreateImageKHR fCreateImageKHR;
         typedef EGLBoolean (GLAPIENTRY * pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image);
         pfnDestroyImageKHR fDestroyImageKHR;
-#ifdef MOZ_WIDGET_GONK
-        typedef EGLBoolean (GLAPIENTRY * pfnSetSwapRectangleANDROID)(EGLDisplay dpy, EGLSurface surface, EGLint left, EGLint top, EGLint width, EGLint height);
-        pfnSetSwapRectangleANDROID fSetSwapRectangleANDROID;
-#endif
 
         // New extension which allow us to lock texture and get raw image pointer
         typedef EGLBoolean (GLAPIENTRY * pfnLockSurfaceKHR)(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
         pfnLockSurfaceKHR fLockSurfaceKHR;
         typedef EGLBoolean (GLAPIENTRY * pfnUnlockSurfaceKHR)(EGLDisplay dpy, EGLSurface surface);
         pfnUnlockSurfaceKHR fUnlockSurfaceKHR;
         typedef EGLBoolean (GLAPIENTRY * pfnQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
         pfnQuerySurface fQuerySurface;
--- a/gfx/layers/d3d9/LayerManagerD3D9Shaders.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9Shaders.h
@@ -480,18 +480,18 @@ const BYTE ComponentPass2ShaderPS[] =
 //   s2D           s0       1
 //
 
     ps_2_0
     def c1, 1, 0, 0, 0
     dcl t0.xy
     dcl_2d s0
     texld r0, t0, s0
-    mul r0.xyz, r0, c0.x
     mov r0.w, c1.x
+    mul r0, r0, c0.x
     mov oC0, r0
 
 // approximately 4 instruction slots used (1 texture, 3 arithmetic)
 #endif
 
 const BYTE RGBShaderPS[] =
 {
       0,   2, 255, 255, 254, 255, 
@@ -531,21 +531,21 @@ const BYTE RGBShaderPS[] =
       0,   0,   0,   0,   0,   0, 
       0,   0,  31,   0,   0,   2, 
       0,   0,   0, 128,   0,   0, 
       3, 176,  31,   0,   0,   2, 
       0,   0,   0, 144,   0,   8, 
      15, 160,  66,   0,   0,   3, 
       0,   0,  15, 128,   0,   0, 
     228, 176,   0,   8, 228, 160, 
+      1,   0,   0,   2,   0,   0, 
+      8, 128,   1,   0,   0, 160, 
       5,   0,   0,   3,   0,   0, 
-      7, 128,   0,   0, 228, 128, 
+     15, 128,   0,   0, 228, 128, 
       0,   0,   0, 160,   1,   0, 
-      0,   2,   0,   0,   8, 128, 
-      1,   0,   0, 160,   1,   0, 
       0,   2,   0,   8,  15, 128, 
       0,   0, 228, 128, 255, 255, 
       0,   0
 };
 #if 0
 //
 // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
 //
--- a/gfx/layers/d3d9/LayerManagerD3D9Shaders.hlsl
+++ b/gfx/layers/d3d9/LayerManagerD3D9Shaders.hlsl
@@ -79,19 +79,19 @@ float4 ComponentPass2Shader(const VS_OUT
 float4 RGBAShader(const VS_OUTPUT aVertex) : COLOR
 {
   return tex2D(s2D, aVertex.vTexCoords) * fLayerOpacity;
 }
 
 float4 RGBShader(const VS_OUTPUT aVertex) : COLOR
 {
   float4 result;
-  result = tex2D(s2D, aVertex.vTexCoords) * fLayerOpacity;
+  result = tex2D(s2D, aVertex.vTexCoords);
   result.a = 1.0;
-  return result;
+  return result * fLayerOpacity;
 }
 
 float4 YCbCrShader(const VS_OUTPUT aVertex) : COLOR
 {
   float4 yuv;
   float4 color;
 
   yuv.r = tex2D(s2DCr, aVertex.vTexCoords).r - 0.5;
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1042,23 +1042,25 @@ gfxFontCache::gfxFontCache()
 {
     mFonts.Init();
 
     nsCOMPtr<nsIObserverService> obs = GetObserverService();
     if (obs) {
         obs->AddObserver(new MemoryPressureObserver, "memory-pressure", false);
     }
 
+#if 0 // disabled due to crashiness, see bug 717175
     mWordCacheExpirationTimer = do_CreateInstance("@mozilla.org/timer;1");
     if (mWordCacheExpirationTimer) {
         mWordCacheExpirationTimer->
             InitWithFuncCallback(WordCacheExpirationTimerCallback, this,
                                  SHAPED_WORD_TIMEOUT_SECONDS * 1000,
                                  nsITimer::TYPE_REPEATING_SLACK);
     }
+#endif
 }
 
 gfxFontCache::~gfxFontCache()
 {
     if (mWordCacheExpirationTimer) {
         mWordCacheExpirationTimer->Cancel();
         mWordCacheExpirationTimer = nsnull;
     }
--- a/hal/Makefile.in
+++ b/hal/Makefile.in
@@ -66,17 +66,16 @@ EXPORTS_mozilla = \
   HalWakeLock.h \
   $(NULL)
 
 CPPSRCS = \
   Hal.cpp \
   SandboxHal.cpp \
   WindowIdentifier.cpp \
   HalWakeLock.cpp \
-  ScreenOrientationFallback.cpp \
   $(NULL)
 
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += \
   AndroidHal.cpp \
   AndroidSensor.cpp \
   $(NULL)
 else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
@@ -106,14 +105,19 @@ CPPSRCS += \
   FallbackSensor.cpp \
   $(NULL)
 endif
 
 ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) #{
 CPPSRCS += FallbackLights.cpp FallbackTime.cpp
 endif #}
 
+# Screen Orientation backend
+ifneq (android,$(MOZ_WIDGET_TOOLKIT))
+CPPSRCS += ScreenOrientationFallback.cpp
+endif
+
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 CFLAGS          += $(MOZ_DBUS_GLIB_CFLAGS)
 CXXFLAGS        += $(MOZ_DBUS_GLIB_CFLAGS)
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -35,16 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Hal.h"
 #include "HalImpl.h"
 #include "WindowIdentifier.h"
 #include "AndroidBridge.h"
 #include "mozilla/dom/network/Constants.h"
+#include "mozilla/dom/ScreenOrientation.h"
 
 using mozilla::hal::WindowIdentifier;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 Vibrate(const nsTArray<uint32> &pattern, const WindowIdentifier &)
@@ -176,11 +177,46 @@ GetCurrentNetworkInformation(hal::Networ
 void
 Reboot()
 {}
 
 void
 PowerOff()
 {}
 
+void
+EnableScreenOrientationNotifications()
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->EnableScreenOrientationNotifications();
+}
+
+void
+DisableScreenOrientationNotifications()
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  bridge->DisableScreenOrientationNotifications();
+}
+
+void
+GetCurrentScreenOrientation(dom::ScreenOrientation* aScreenOrientation)
+{
+  AndroidBridge* bridge = AndroidBridge::Bridge();
+  if (!bridge) {
+    return;
+  }
+
+  dom::ScreenOrientationWrapper orientationWrapper;
+  bridge->GetScreenOrientation(orientationWrapper);
+  *aScreenOrientation = orientationWrapper.orientation;
+}
+
 } // hal_impl
 } // mozilla
 
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -34,17 +34,17 @@
  * 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 protocol PContent;
 include protocol PBrowser;
-include "nspr/prtime.h";
+include "prtime.h";
 include "mozilla/HalSensor.h";
 include "mozilla/HalTypes.h";
 include "mozilla/dom/ScreenOrientation.h";
 
 using PRTime;
 using mozilla::hal::FlashMode;
 using mozilla::hal::LightType;
 using mozilla::hal::LightMode;
--- a/image/src/DiscardTracker.cpp
+++ b/image/src/DiscardTracker.cpp
@@ -148,22 +148,22 @@ DiscardTracker::Initialize()
 
   Preferences::AddUintVarCache(&sMaxDecodedImageKB,
                               "image.mem.max_decoded_image_kb",
                               50 * 1024);
 
   // Create the timer.
   sTimer = do_CreateInstance("@mozilla.org/timer;1");
 
+  // Mark us as initialized
+  sInitialized = true;
+
   // Read the timeout pref and start the timer.
   ReloadTimeout();
 
-  // Mark us as initialized
-  sInitialized = true;
-
   return NS_OK;
 }
 
 /**
  * Read the discard timeout from about:config.
  */
 void
 DiscardTracker::ReloadTimeout()
@@ -189,19 +189,22 @@ DiscardTracker::ReloadTimeout()
 }
 
 /**
  * Enables the timer. No-op if the timer is already running.
  */
 nsresult
 DiscardTracker::EnableTimer()
 {
-  // Nothing to do if the timer's already on.
-  if (sTimerOn)
+  // Nothing to do if the timer's already on or we haven't yet been
+  // initialized.  !sTimer probably means we've shut down, so just ignore that,
+  // too.
+  if (sTimerOn || !sInitialized || !sTimer)
     return NS_OK;
+
   sTimerOn = true;
 
   // Activate the timer.  Have it call us back in (sMinDiscardTimeoutMs / 2)
   // ms, so that an image is discarded between sMinDiscardTimeoutMs and
   // (3/2 * sMinDiscardTimeoutMs) ms after it's unlocked.
   return sTimer->InitWithFuncCallback(TimerCallback,
                                       nsnull,
                                       sMinDiscardTimeoutMs / 2,
@@ -210,17 +213,17 @@ DiscardTracker::EnableTimer()
 
 /*
  * Disables the timer. No-op if the timer isn't running.
  */
 void
 DiscardTracker::DisableTimer()
 {
   // Nothing to do if the timer's already off.
-  if (!sTimerOn)
+  if (!sTimerOn || !sTimer)
     return;
   sTimerOn = false;
 
   // Deactivate
   sTimer->Cancel();
 }
 
 /**
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -286,46 +286,55 @@ HeapId::init(jsid id)
     value = id;
     post();
 }
 
 inline void
 HeapId::pre()
 {
 #ifdef JSGC_INCREMENTAL
-    if (JS_UNLIKELY(JSID_IS_OBJECT(value))) {
+    if (JSID_IS_OBJECT(value)) {
         JSObject *obj = JSID_TO_OBJECT(value);
         JSCompartment *comp = obj->compartment();
         if (comp->needsBarrier()) {
             js::gc::MarkObjectUnbarriered(comp->barrierTracer(), &obj, "write barrier");
             JS_ASSERT(obj == JSID_TO_OBJECT(value));
         }
+    } else if (JSID_IS_STRING(value)) {
+        JSString *str = JSID_TO_STRING(value);
+        JSCompartment *comp = str->compartment();
+        if (comp->needsBarrier()) {
+            js::gc::MarkStringUnbarriered(comp->barrierTracer(), &str, "write barrier");
+            JS_ASSERT(str == JSID_TO_STRING(value));
+        }
     }
 #endif
 }
 
 inline void
 HeapId::post()
 {
 }
 
 inline HeapId &
 HeapId::operator=(jsid id)
 {
-    pre();
+    if (id != value)
+        pre();
     JS_ASSERT(!IsPoisonedId(id));
     value = id;
     post();
     return *this;
 }
 
 inline HeapId &
 HeapId::operator=(const HeapId &v)
 {
-    pre();
+    if (v.value != value)
+        pre();
     JS_ASSERT(!IsPoisonedId(v.value));
     value = v.value;
     post();
     return *this;
 }
 
 inline const Value &
 ReadBarrieredValue::get() const
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -244,16 +244,17 @@ BarrieredSetPair(JSCompartment *comp,
     v1.post();
     v2.post();
 }
 
 struct Shape;
 class BaseShape;
 namespace types { struct TypeObject; }
 
+typedef HeapPtr<JSAtom> HeapPtrAtom;
 typedef HeapPtr<JSObject> HeapPtrObject;
 typedef HeapPtr<JSFunction> HeapPtrFunction;
 typedef HeapPtr<JSString> HeapPtrString;
 typedef HeapPtr<JSScript> HeapPtrScript;
 typedef HeapPtr<Shape> HeapPtrShape;
 typedef HeapPtr<BaseShape> HeapPtrBaseShape;
 typedef HeapPtr<types::TypeObject> HeapPtrTypeObject;
 typedef HeapPtr<JSXML> HeapPtrXML;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug737575.js
@@ -0,0 +1,6 @@
+function f(s) {
+    return arguments[s];
+}
+
+for (var i = 0; i < 10; ++i)
+    assertEq(f(String(i+1), 0,1,2,3,4,5,6,7,8,9), i);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testWeirdGetterInvocation.js
@@ -0,0 +1,6 @@
+function getArgs() { return arguments; }
+var a1 = getArgs(1);
+var a2 = getArgs(1);
+a1.__proto__ = a2;
+delete a1[0];
+a1[0];
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -483,16 +483,17 @@ fun_resolve(JSContext *cx, JSObject *obj
 #if JS_HAS_XDR
 
 /* XXX store parent and proto, if defined */
 JSBool
 js::XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
 {
     JSContext *cx;
     JSFunction *fun;
+    JSAtom *atom;
     uint32_t firstword;           /* flag telling whether fun->atom is non-null,
                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
                                    and 14 bits reserved for future use */
     uint32_t flagsword;           /* word for argument count and fun->flags */
 
     cx = xdr->cx;
     JSScript *script;
     if (xdr->mode == JSXDR_ENCODE) {
@@ -502,44 +503,47 @@ js::XDRFunctionObject(JSXDRState *xdr, J
             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
                                      name);
             }
             return false;
         }
         firstword = !!fun->atom;
         flagsword = (fun->nargs << 16) | fun->flags;
+        atom = fun->atom;
         script = fun->script();
     } else {
         RootedVarObject parent(cx, NULL);
         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL);
         if (!fun)
             return false;
         if (!fun->clearParent(cx))
             return false;
         if (!fun->clearType(cx))
             return false;
+        atom = NULL;
         script = NULL;
     }
 
     if (!JS_XDRUint32(xdr, &firstword))
         return false;
-    if ((firstword & 1U) && !js_XDRAtom(xdr, &fun->atom))
+    if ((firstword & 1U) && !js_XDRAtom(xdr, &atom))
         return false;
     if (!JS_XDRUint32(xdr, &flagsword))
         return false;
 
     if (!XDRScript(xdr, &script))
         return false;
 
     if (xdr->mode == JSXDR_DECODE) {
         fun->nargs = flagsword >> 16;
         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         fun->flags = uint16_t(flagsword);
-        fun->setScript(script);
+        fun->atom.init(atom);
+        fun->initScript(script);
         if (!script->typeSetFunction(cx, fun))
             return false;
         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
         *objp = fun;
     }
 
     return true;
@@ -582,17 +586,17 @@ inline void
 JSFunction::trace(JSTracer *trc)
 {
     if (isExtended()) {
         MarkValueRange(trc, ArrayLength(toExtended()->extendedSlots),
                        toExtended()->extendedSlots, "nativeReserved");
     }
 
     if (atom)
-        MarkStringUnbarriered(trc, &atom, "atom");
+        MarkString(trc, &atom, "atom");
 
     if (isInterpreted()) {
         if (u.i.script_)
             MarkScriptUnbarriered(trc, &u.i.script_, "script");
         if (u.i.env_)
             MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope");
     }
 }
@@ -1003,17 +1007,17 @@ fun_bind(JSContext *cx, unsigned argc, V
     unsigned length = 0;
     if (target->isFunction()) {
         unsigned nargs = target->toFunction()->nargs;
         if (nargs > argslen)
             length = nargs - argslen;
     }
 
     /* Step 4-6, 10-11. */
-    JSAtom *name = target->isFunction() ? target->toFunction()->atom : NULL;
+    JSAtom *name = target->isFunction() ? target->toFunction()->atom.get() : NULL;
 
     JSObject *funobj =
         js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
                        JSFUN_CONSTRUCTOR, target, name);
     if (!funobj)
         return false;
 
     /* NB: Bound functions abuse |parent| to store their target. */
@@ -1299,17 +1303,17 @@ js_NewFunction(JSContext *cx, JSObject *
         fun->u.n.clasp = NULL;
         fun->u.n.native = native;
         JS_ASSERT(fun->u.n.native);
     }
     if (kind == JSFunction::ExtendedFinalizeKind) {
         fun->flags |= JSFUN_EXTENDED;
         fun->initializeExtended();
     }
-    fun->atom = atom;
+    fun->atom.init(atom);
 
     if (native && !fun->setSingletonType(cx))
         return NULL;
 
     return fun;
 }
 
 JSFunction * JS_FASTCALL
@@ -1327,17 +1331,17 @@ js_CloneFunctionObject(JSContext *cx, JS
     clone->nargs = fun->nargs;
     clone->flags = fun->flags & ~JSFUN_EXTENDED;
     if (fun->isInterpreted()) {
         clone->initScript(fun->script());
         clone->initEnvironment(parent);
     } else {
         clone->u.n = fun->u.n;
     }
-    clone->atom = fun->atom;
+    clone->atom.init(fun->atom);
 
     if (kind == JSFunction::ExtendedFinalizeKind) {
         clone->flags |= JSFUN_EXTENDED;
         clone->initializeExtended();
     }
 
     if (cx->compartment == fun->compartment()) {
         /*
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -97,17 +97,17 @@ struct JSFunction : public JSObject
         struct Scripted {
             JSScript    *script_; /* interpreted bytecode descriptor or null;
                                      use the accessor! */
             JSObject    *env_;    /* environment for new activations;
                                      use the accessor! */
         } i;
         void            *nativeOrScript;
     } u;
-    JSAtom          *atom;        /* name for diagnostics and decompiling */
+    js::HeapPtrAtom  atom;        /* name for diagnostics and decompiling */
 
     bool optimizedClosure()  const { return kind() > JSFUN_INTERPRETED; }
     bool isInterpreted()     const { return kind() >= JSFUN_INTERPRETED; }
     bool isNative()          const { return !isInterpreted(); }
     bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
     bool isHeavyweight()     const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
     bool isNullClosure()     const { return kind() == JSFUN_NULL_CLOSURE; }
     bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -674,35 +674,38 @@ TypeSet::addCall(JSContext *cx, TypeCall
 {
     add(cx, cx->typeLifoAlloc().new_<TypeConstraintCall>(site));
 }
 
 /* Constraints for arithmetic operations. */
 class TypeConstraintArith : public TypeConstraint
 {
 public:
+    JSScript *script;
+    jsbytecode *pc;
+
     /* Type set receiving the result of the arithmetic. */
     TypeSet *target;
 
     /* For addition operations, the other operand. */
     TypeSet *other;
 
-    TypeConstraintArith(TypeSet *target, TypeSet *other)
-        : TypeConstraint("arith"), target(target), other(other)
+    TypeConstraintArith(JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
+        : TypeConstraint("arith"), script(script), pc(pc), target(target), other(other)
     {
         JS_ASSERT(target);
     }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
-TypeSet::addArith(JSContext *cx, TypeSet *target, TypeSet *other)
-{
-    add(cx, cx->typeLifoAlloc().new_<TypeConstraintArith>(target, other));
+TypeSet::addArith(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
+{
+    add(cx, cx->typeLifoAlloc().new_<TypeConstraintArith>(script, pc, target, other));
 }
 
 /* Subset constraint which transforms primitive values into appropriate objects. */
 class TypeConstraintTransformThis : public TypeConstraint
 {
 public:
     JSScript *script;
     TypeSet *target;
@@ -1295,37 +1298,39 @@ TypeConstraintArith::newType(JSContext *
          *   double x {int,bool,double} -> double
          *   string x any -> string
          */
         if (type.isUnknown() || other->unknown()) {
             target->addType(cx, Type::UnknownType());
         } else if (type.isPrimitive(JSVAL_TYPE_DOUBLE)) {
             if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
                                   TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_BOOLEAN |
-                                  TYPE_FLAG_ANYOBJECT) ||
-                other->getObjectCount() != 0) {
+                                  TYPE_FLAG_ANYOBJECT)) {
                 target->addType(cx, Type::DoubleType());
+            } else if (other->getObjectCount() != 0) {
+                TypeDynamicResult(cx, script, pc, Type::DoubleType());
             }
         } else if (type.isPrimitive(JSVAL_TYPE_STRING)) {
             target->addType(cx, Type::StringType());
-        } else {
-            if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
-                                  TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN |
-                                  TYPE_FLAG_ANYOBJECT) ||
-                other->getObjectCount() != 0) {
-                target->addType(cx, Type::Int32Type());
-            }
-            if (other->hasAnyFlag(TYPE_FLAG_DOUBLE))
-                target->addType(cx, Type::DoubleType());
+        } else if (other->hasAnyFlag(TYPE_FLAG_DOUBLE)) {
+            target->addType(cx, Type::DoubleType());
+        } else if (other->hasAnyFlag(TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL |
+                                     TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN |
+                                     TYPE_FLAG_ANYOBJECT)) {
+            target->addType(cx, Type::Int32Type());
+        } else if (other->getObjectCount() != 0) {
+            TypeDynamicResult(cx, script, pc, Type::Int32Type());
         }
     } else {
         if (type.isUnknown())
             target->addType(cx, Type::UnknownType());
         else if (type.isPrimitive(JSVAL_TYPE_DOUBLE))
             target->addType(cx, Type::DoubleType());
+        else if (!type.isAnyObject() && type.isObject())
+            TypeDynamicResult(cx, script, pc, Type::Int32Type());
         else
             target->addType(cx, Type::Int32Type());
     }
 }
 
 void
 TypeConstraintTransformThis::newType(JSContext *cx, TypeSet *source, Type type)
 {
@@ -3621,20 +3626,20 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC: {
         uint32_t slot = GetBytecodeSlot(script, pc);
         if (trackSlot(slot)) {
-            poppedTypes(pc, 0)->addArith(cx, &pushed[0]);
+            poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
         } else if (slot < TotalSlots(script)) {
             TypeSet *types = TypeScript::SlotTypes(script, slot);
-            types->addArith(cx, types);
+            types->addArith(cx, script, pc, types);
             types->addSubset(cx, &pushed[0]);
         } else {
             pushed[0].addType(cx, Type::UnknownType());
         }
         break;
       }
 
       case JSOP_ARGUMENTS:
@@ -3707,31 +3712,31 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       case JSOP_RETURN:
       case JSOP_SETRVAL:
           if (script->function())
             poppedTypes(pc, 0)->addSubset(cx, TypeScript::ReturnTypes(script));
         break;
 
       case JSOP_ADD:
-        poppedTypes(pc, 0)->addArith(cx, &pushed[0], poppedTypes(pc, 1));
-        poppedTypes(pc, 1)->addArith(cx, &pushed[0], poppedTypes(pc, 0));
+        poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 1));
+        poppedTypes(pc, 1)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 0));
         break;
 
       case JSOP_SUB:
       case JSOP_MUL:
       case JSOP_MOD:
       case JSOP_DIV:
-        poppedTypes(pc, 0)->addArith(cx, &pushed[0]);
-        poppedTypes(pc, 1)->addArith(cx, &pushed[0]);
+        poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
+        poppedTypes(pc, 1)->addArith(cx, script, pc, &pushed[0]);
         break;
 
       case JSOP_NEG:
       case JSOP_POS:
-        poppedTypes(pc, 0)->addArith(cx, &pushed[0]);
+        poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
         break;
 
       case JSOP_LAMBDA:
       case JSOP_DEFFUN:
       case JSOP_DEFLOCALFUN: {
         unsigned off = op == JSOP_DEFLOCALFUN ? SLOTNO_LEN : 0;
         JSObject *obj = script->getObject(GET_UINT32_INDEX(pc + off));
 
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -436,17 +436,18 @@ class TypeSet
     void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
                         TypeSet *target, jsid id);
     void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
                         TypeSet *target, jsid id);
     void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
     void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
                        TypeSet *objectTypes, TypeSet *valueTypes);
     void addCall(JSContext *cx, TypeCallsite *site);
-    void addArith(JSContext *cx, TypeSet *target, TypeSet *other = NULL);
+    void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
+                  TypeSet *target, TypeSet *other = NULL);
     void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
     void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
                           Type type, TypeSet *types = NULL);
     void addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter);
     void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
 
     /*
      * Make an type set with the specified debugging name, not embedded in
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -6242,17 +6242,16 @@ dumpValue(const Value &v)
             fprintf(stderr, "true");
         else
             fprintf(stderr, "false");
     } else if (v.isMagic()) {
         fprintf(stderr, "<invalid");
 #ifdef DEBUG
         switch (v.whyMagic()) {
           case JS_ARRAY_HOLE:        fprintf(stderr, " array hole");         break;
-          case JS_ARGS_HOLE:         fprintf(stderr, " args hole");          break;
           case JS_NATIVE_ENUMERATE:  fprintf(stderr, " native enumeration"); break;
           case JS_NO_ITER_VALUE:     fprintf(stderr, " no iter value");      break;
           case JS_GENERATOR_CLOSING: fprintf(stderr, " generator closing");  break;
           default:                   fprintf(stderr, " ?!");                 break;
         }
 #endif
         fprintf(stderr, ">");
     } else {
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -661,29 +661,29 @@ namespace js {
 
 /*
  * Any name atom for a function which will be added as a DeclEnv object to the
  * scope chain above call objects for fun.
  */
 static inline JSAtom *
 CallObjectLambdaName(JSFunction *fun)
 {
-    return (fun->flags & JSFUN_LAMBDA) ? fun->atom : NULL;
+    return (fun->flags & JSFUN_LAMBDA) ? fun->atom.get() : NULL;
 }
 
 } /* namespace js */
 
 inline const js::Value &
 JSObject::getDateUTCTime() const
 {
     JS_ASSERT(isDate());
     return getFixedSlot(JSSLOT_DATE_UTC_TIME);
 }
 
-inline void 
+inline void
 JSObject::setDateUTCTime(const js::Value &time)
 {
     JS_ASSERT(isDate());
     setFixedSlot(JSSLOT_DATE_UTC_TIME, time);
 }
 
 inline js::NativeIterator *
 JSObject::getNativeIterator() const
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -320,20 +320,19 @@ ScriptFilename(const JSScript *script)
     return script->filename;
 }
 
 static const char *
 FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString* bytes)
 {
     if (!fun)
         return Probes::nullName;
-    JSAtom *atom = const_cast<JSAtom*>(fun->atom);
-    if (!atom)
+    if (!fun->atom)
         return Probes::anonymousName;
-    return bytes->encode(cx, atom) ? bytes->ptr() : Probes::nullName;
+    return bytes->encode(cx, fun->atom) ? bytes->ptr() : Probes::nullName;
 }
 
 static const char *
 FunctionClassname(const JSFunction *fun)
 {
     if (!fun || fun->isInterpreted())
         return Probes::nullName;
     if (fun->getConstructorClass())
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -315,16 +315,76 @@ UnsignedPtrDiff(const void *bigger, cons
  * 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 };
 
+/*****************************************************************************/
+
+/* A bit array is an array of bits represented by an array of words (size_t). */
+
+static inline unsigned
+NumWordsForBitArrayOfLength(size_t length)
+{
+    return (length + (JS_BITS_PER_WORD - 1)) / JS_BITS_PER_WORD;
+}
+
+static inline unsigned
+BitArrayIndexToWordIndex(size_t length, size_t bitIndex)
+{
+    unsigned wordIndex = bitIndex / JS_BITS_PER_WORD;
+    JS_ASSERT(wordIndex < length);
+    return wordIndex;
+}
+
+static inline size_t
+BitArrayIndexToWordMask(size_t i)
+{
+    return size_t(1) << (i % JS_BITS_PER_WORD);
+}
+
+static inline bool
+IsBitArrayElementSet(size_t *array, size_t length, size_t i)
+{
+    return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i);
+}
+
+static inline bool
+IsAnyBitArrayElementSet(size_t *array, size_t length)
+{
+    unsigned numWords = NumWordsForBitArrayOfLength(length);
+    for (unsigned i = 0; i < numWords; ++i) {
+        if (array[i])
+            return true;
+    }
+    return false;
+}
+
+static inline void
+SetBitArrayElement(size_t *array, size_t length, size_t i)
+{
+    array[BitArrayIndexToWordIndex(length, i)] |= BitArrayIndexToWordMask(i);
+}
+
+static inline void
+ClearBitArrayElement(size_t *array, size_t length, size_t i)
+{
+    array[BitArrayIndexToWordIndex(length, i)] &= ~BitArrayIndexToWordMask(i);
+}
+
+static inline void
+ClearAllBitArrayElements(size_t *array, size_t length)
+{
+    for (unsigned i = 0; i < length; ++i)
+        array[i] = 0;
+}
+
 }  /* namespace js */
 #endif  /* __cplusplus */
 
 /*
  * JS_ROTATE_LEFT32
  *
  * There is no rotate operation in the C Language so the construct (a << 4) |
  * (a >> 28) is used instead. Most compilers convert this to a rotate
--- a/js/src/jsval.h
+++ b/js/src/jsval.h
@@ -275,17 +275,16 @@ typedef uint64_t JSValueShiftedTag;
 #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET       JSVAL_SHIFTED_TAG_UNDEFINED
 #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET      JSVAL_SHIFTED_TAG_STRING
 
 #endif /* JS_BITS_PER_WORD */
 
 typedef enum JSWhyMagic
 {
     JS_ARRAY_HOLE,               /* a hole in a dense array */
-    JS_ARGS_HOLE,                /* a hole in the args object's array */
     JS_NATIVE_ENUMERATE,         /* indicates that a custom enumerate hook forwarded
                                   * to JS_EnumerateState, which really means the object can be
                                   * enumerated like a native object. */
     JS_NO_ITER_VALUE,            /* there is not a pending iterator value */
     JS_GENERATOR_CLOSING,        /* exception value thrown when closing a generator */
     JS_NO_CONSTANT,              /* compiler sentinel value */
     JS_THIS_POISON,              /* used in debug builds to catch tracing errors */
     JS_ARG_POISON,               /* used in debug builds to catch tracing errors */
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -859,57 +859,16 @@ class GetPropCompiler : public PICStubCo
         }
 
         JS_ASSERT(pic.kind == ic::PICInfo::GET);
 
         FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, ic::GetProp));
         repatcher.relink(pic.slowPathCall, target);
     }
 
-    LookupStatus generateArgsLengthStub()
-    {
-        Assembler masm;
-
-        Jump notArgs = masm.guardShape(pic.objReg, obj);
-
-        masm.load32(Address(pic.objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), pic.objReg);
-        masm.move(pic.objReg, pic.shapeReg);
-        Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg,
-                                            Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
-        masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), pic.objReg);
-
-        masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
-        Jump done = masm.jump();
-
-        pic.updatePCCounters(f, masm);
-
-        PICLinker buffer(masm, pic);
-        if (!buffer.init(cx))
-            return error();
-
-        if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
-            !buffer.verifyRange(f.chunk())) {
-            return disable("code memory is out of range");
-        }
-
-        buffer.link(notArgs, pic.slowPathStart);
-        buffer.link(overridden, pic.slowPathStart);
-        buffer.link(done, pic.fastPathRejoin);
-
-        CodeLocationLabel start = buffer.finalize(f);
-        JaegerSpew(JSpew_PICs, "generate args length stub at %p\n",
-                   start.executableAddress());
-
-        patchPreviousToHere(start);
-
-        disable("args length done");
-
-        return Lookup_Cacheable;
-    }
-
     LookupStatus generateArrayLengthStub()
     {
         Assembler masm;
 
         masm.loadObjClass(pic.objReg, pic.shapeReg);
         Jump isDense = masm.testClass(Assembler::Equal, pic.shapeReg, &ArrayClass);
         Jump notArray = masm.testClass(Assembler::NotEqual, pic.shapeReg, &SlowArrayClass);
 
@@ -1878,31 +1837,24 @@ GetPropMaybeCached(VMFrame &f, ic::PICIn
     PropertyName *name = pic->name;
     if (name == f.cx->runtime->atomState.lengthAtom) {
         if (f.regs.sp[-1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
             f.regs.sp[-1].setInt32(f.regs.fp()->numActualArgs());
             return;
         }
         if (!f.regs.sp[-1].isPrimitive()) {
             JSObject *obj = &f.regs.sp[-1].toObject();
-            if (obj->isArray() ||
-                (obj->isArguments() && !obj->asArguments().hasOverriddenLength()) ||
-                obj->isString()) {
+            if (obj->isArray() || obj->isString()) {
                 GetPropCompiler cc(f, script, obj, *pic, NULL, stub);
                 if (obj->isArray()) {
                     LookupStatus status = cc.generateArrayLengthStub();
                     if (status == Lookup_Error)
                         THROW();
                     f.regs.sp[-1].setNumber(obj->getArrayLength());
-                } else if (obj->isArguments()) {
-                    LookupStatus status = cc.generateArgsLengthStub();
-                    if (status == Lookup_Error)
-                        THROW();
-                    f.regs.sp[-1].setInt32(int32_t(obj->asArguments().initialLength()));
-                } else if (obj->isString()) {
+                } else {
                     LookupStatus status = cc.generateStringObjLengthStub();
                     if (status == Lookup_Error)
                         THROW();
                     JSString *str = obj->asString().unbox();
                     f.regs.sp[-1].setInt32(str->length());
                 }
                 return;
             }
@@ -2363,168 +2315,16 @@ GetElementIC::attachGetProp(VMFrame &f, 
         disable(f, "max stubs reached");
 
     // Finally, fetch the value to avoid redoing the property lookup.
     *vp = holder->getSlot(shape->slot());
 
     return Lookup_Cacheable;
 }
 
-LookupStatus
-GetElementIC::attachArguments(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
-{
-    JSContext *cx = f.cx;
-
-    if (!v.isInt32())
-        return disable(f, "arguments object with non-integer key");
-
-    if (op == JSOP_CALLELEM)
-        return disable(f, "arguments object with call");
-
-    JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
-
-    Assembler masm;
-
-    Jump shapeGuard = masm.testObjClass(Assembler::NotEqual, objReg, typeReg, obj->getClass());
-
-    masm.move(objReg, typeReg);
-    masm.load32(Address(objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), 
-                objReg);
-    Jump overridden = masm.branchTest32(Assembler::NonZero, objReg,
-                                        Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
-    masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), objReg);
-
-    Jump outOfBounds;
-    if (idRemat.isConstant()) {
-        outOfBounds = masm.branch32(Assembler::BelowOrEqual, objReg, Imm32(v.toInt32()));
-    } else {
-        outOfBounds = masm.branch32(Assembler::BelowOrEqual, objReg, idRemat.dataReg());
-    }
-
-    masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::DATA_SLOT)), objReg);
-    if (idRemat.isConstant()) {
-        Address slot(objReg, offsetof(ArgumentsData, slots) + v.toInt32() * sizeof(Value));
-        masm.loadTypeTag(slot, objReg);
-    } else {
-        BaseIndex slot(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE, 
-                       offsetof(ArgumentsData, slots));
-        masm.loadTypeTag(slot, objReg);
-    }    
-    Jump holeCheck = masm.branchPtr(Assembler::Equal, objReg, ImmType(JSVAL_TYPE_MAGIC));
-
-    masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::STACK_FRAME_SLOT)), objReg);
-    Jump liveArguments = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(0));
-   
-    masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::DATA_SLOT)), objReg);
-
-    if (idRemat.isConstant()) {
-        Address slot(objReg, offsetof(ArgumentsData, slots) + v.toInt32() * sizeof(Value));
-        masm.loadValueAsComponents(slot, typeReg, objReg);           
-    } else {
-        BaseIndex slot(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE, 
-                       offsetof(ArgumentsData, slots));
-        masm.loadValueAsComponents(slot, typeReg, objReg);
-    }
-
-    Jump done = masm.jump();
-
-    liveArguments.linkTo(masm.label(), &masm);
-
-    masm.move(objReg, typeReg);
-
-    Address fun(typeReg, StackFrame::offsetOfExec());
-    masm.loadPtr(fun, objReg);
-
-    Address nargs(objReg, offsetof(JSFunction, nargs));
-    masm.load16(nargs, objReg);
-
-    Jump notFormalArg;
-    if (idRemat.isConstant())
-        notFormalArg = masm.branch32(Assembler::BelowOrEqual, objReg, Imm32(v.toInt32()));
-    else
-        notFormalArg = masm.branch32(Assembler::BelowOrEqual, objReg, idRemat.dataReg());
-
-    masm.lshift32(Imm32(3), objReg); /* nargs << 3 == nargs * sizeof(Value) */
-    masm.subPtr(objReg, typeReg); /* fp - numFormalArgs => start of formal args */
-
-    Label loadFromStack = masm.label();
-    masm.move(typeReg, objReg);
-
-    if (idRemat.isConstant()) {
-        Address frameEntry(objReg, v.toInt32() * sizeof(Value));
-        masm.loadValueAsComponents(frameEntry, typeReg, objReg);
-    } else {
-        BaseIndex frameEntry(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE);
-        masm.loadValueAsComponents(frameEntry, typeReg, objReg);
-    }    
-    Jump done2 = masm.jump();
-
-    notFormalArg.linkTo(masm.label(), &masm);
-
-    masm.push(typeReg);
-
-    Address argsObject(typeReg, StackFrame::offsetOfArgsObj());
-    masm.loadPtr(argsObject, typeReg);
-
-    masm.load32(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), 
-                typeReg); 
-    masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), typeReg); 
-
-    /* This basically does fp - (numFormalArgs + numActualArgs + 2) */
-
-    masm.addPtr(typeReg, objReg);
-    masm.addPtr(Imm32(2), objReg);
-    masm.lshiftPtr(Imm32(3), objReg);
-
-    masm.pop(typeReg);
-    masm.subPtr(objReg, typeReg);
-
-    masm.jump(loadFromStack);
-
-    updatePCCounters(f, masm);
-
-    PICLinker buffer(masm, *this);
-
-    if (!buffer.init(cx))
-        return error(cx);
-
-    if (!buffer.verifyRange(f.chunk()))
-        return disable(f, "code memory is out of range");
-
-    buffer.link(shapeGuard, slowPathStart);
-    buffer.link(overridden, slowPathStart);
-    buffer.link(outOfBounds, slowPathStart);
-    buffer.link(holeCheck, slowPathStart);
-    buffer.link(done, fastPathRejoin);    
-    buffer.link(done2, fastPathRejoin);
-    
-    CodeLocationLabel cs = buffer.finalizeCodeAddendum();
-
-    JaegerSpew(JSpew_PICs, "generated getelem arguments stub at %p\n", cs.executableAddress());
-
-    Repatcher repatcher(f.chunk());
-    repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
-
-    JS_ASSERT(!shouldPatchUnconditionalShapeGuard());
-    JS_ASSERT(!inlineShapeGuardPatched);
-
-    inlineShapeGuardPatched = true;
-    stubsGenerated++;
-
-    if (stubsGenerated == MAX_GETELEM_IC_STUBS)
-        disable(f, "max stubs reached");
-
-    disable(f, "generated arguments stub");
-
-    if (!obj->getGeneric(cx, id, vp))
-        return Lookup_Error;
-
-    return Lookup_Cacheable;
-}
-
 #if defined JS_METHODJIT_TYPED_ARRAY
 LookupStatus
 GetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
 {
     JSContext *cx = f.cx;
 
     if (!v.isInt32())
         return disable(f, "typed array with string key");
@@ -2622,19 +2422,16 @@ GetElementIC::update(VMFrame &f, JSObjec
      * GETPROP IC assumes the id has already gone through filtering for string
      * indexes in the emitter, i.e. js_GetProtoIfDenseArray is only valid to
      * use when looking up non-integer identifiers.
      */
     uint32_t dummy;
     if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy))
         return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);
 
-    if (obj->isArguments())
-        return attachArguments(f, obj, v, id, vp);
-
 #if defined JS_METHODJIT_TYPED_ARRAY
     /*
      * Typed array ICs can make stub calls, and need to know which registers
      * are in use and need to be restored after the call. If type inference is
      * enabled then we don't necessarily know the full set of such registers
      * when generating the IC (loop-carried registers may be allocated later),
      * and additionally the push/pop instructions used to save/restore in the
      * IC are not compatible with carrying entries in floating point registers.
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -296,17 +296,16 @@ struct GetElementIC : public BasePolyIC 
         inlineShapeGuardPatched = false;
         typeRegHasBaseShape = false;
         hasLastStringStub = false;
     }
     void purge(Repatcher &repatcher);
     LookupStatus update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
     LookupStatus attachGetProp(VMFrame &f, JSObject *obj, const Value &v, PropertyName *name,
                                Value *vp);
-    LookupStatus attachArguments(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
     LookupStatus attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
     LookupStatus disable(VMFrame &f, const char *reason);
     LookupStatus error(JSContext *cx);
     bool shouldUpdate(JSContext *cx);
 };
 
 struct SetElementIC : public BaseIC {
     SetElementIC() : execPool(NULL) { reset(); }
--- a/js/src/vm/ArgumentsObject-inl.h
+++ b/js/src/vm/ArgumentsObject-inl.h
@@ -84,101 +84,101 @@ ArgumentsObject::initData(ArgumentsData 
 }
 
 inline ArgumentsData *
 ArgumentsObject::data() const
 {
     return reinterpret_cast<js::ArgumentsData *>(getFixedSlot(DATA_SLOT).toPrivate());
 }
 
+inline bool
+ArgumentsObject::isElementDeleted(uint32_t i) const
+{
+    return IsBitArrayElementSet(data()->deletedBits, initialLength(), i);
+}
+
+inline bool
+ArgumentsObject::isAnyElementDeleted() const
+{
+    return IsAnyBitArrayElementSet(data()->deletedBits, initialLength());
+}
+
+inline void
+ArgumentsObject::markElementDeleted(uint32_t i)
+{
+    SetBitArrayElement(data()->deletedBits, initialLength(), i);
+}
+
 inline const js::Value &
 ArgumentsObject::element(uint32_t i) const
 {
-    JS_ASSERT(i < initialLength());
+    JS_ASSERT(!isElementDeleted(i));
     return data()->slots[i];
 }
 
-inline const js::Value *
-ArgumentsObject::elements() const
-{
-    return Valueify(data()->slots);
-}
-
 inline void
 ArgumentsObject::setElement(uint32_t i, const js::Value &v)
 {
-    JS_ASSERT(i < initialLength());
+    JS_ASSERT(!isElementDeleted(i));
     data()->slots[i] = v;
 }
 
 inline bool
 ArgumentsObject::getElement(uint32_t i, Value *vp)
 {
-    if (i >= initialLength())
-        return false;
-
-    *vp = element(i);
-
-    /*
-     * If the argument was overwritten, it could be in any object slot, so we
-     * can't optimize.
-     */
-    if (vp->isMagic(JS_ARGS_HOLE))
+    if (i >= initialLength() || isElementDeleted(i))
         return false;
 
     /*
      * If this arguments object has an associated stack frame, that contains
      * the canonical argument value.  Note that strict arguments objects do not
      * alias named arguments and never have a stack frame.
      */
     StackFrame *fp = maybeStackFrame();
     JS_ASSERT_IF(isStrictArguments(), !fp);
     if (fp)
         *vp = fp->canonicalActualArg(i);
+    else
+        *vp = element(i);
     return true;
 }
 
 namespace detail {
 
 struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo
 {
     CopyNonHoleArgsTo(ArgumentsObject *argsobj, Value *dst) : argsobj(*argsobj), dst(dst) {}
     ArgumentsObject &argsobj;
     Value *dst;
     bool operator()(uint32_t argi, Value *src) {
-        if (argsobj.element(argi).isMagic(JS_ARGS_HOLE))
-            return false;
         *dst++ = *src;
         return true;
     }
 };
 
 } /* namespace detail */
 
 inline bool
 ArgumentsObject::getElements(uint32_t start, uint32_t count, Value *vp)
 {
     JS_ASSERT(start + count >= start);
 
     uint32_t length = initialLength();
-    if (start > length || start + count > length)
+    if (start > length || start + count > length || isAnyElementDeleted())
         return false;
 
     StackFrame *fp = maybeStackFrame();
 
     /* If there's no stack frame for this, argument values are in elements(). */
     if (!fp) {
-        const Value *srcbeg = elements() + start;
+        const Value *srcbeg = Valueify(data()->slots) + start;
         const Value *srcend = srcbeg + count;
         const Value *src = srcbeg;
-        for (Value *dst = vp; src < srcend; ++dst, ++src) {
-            if (src->isMagic(JS_ARGS_HOLE))
-                return false;
+        for (Value *dst = vp; src < srcend; ++dst, ++src)
             *dst = *src;
-        }
         return true;
     }
 
     /* Otherwise, element values are on the stack. */
     JS_ASSERT(fp->numActualArgs() <= StackSpace::ARGS_LENGTH_MAX);
     return fp->forEachCanonicalActualArg(detail::CopyNonHoleArgsTo(this, vp), start, count);
 }
 
@@ -204,14 +204,14 @@ inline const js::Value &
 NormalArgumentsObject::callee() const
 {
     return data()->callee;
 }
 
 inline void
 NormalArgumentsObject::clearCallee()
 {
-    data()->callee.set(compartment(), MagicValue(JS_ARGS_HOLE));
+    data()->callee.set(compartment(), MagicValue(JS_OVERWRITTEN_CALLEE));
 }
 
 } // namespace js
 
 #endif /* ArgumentsObject_inl_h___ */
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -51,36 +51,38 @@
 #include "gc/Barrier-inl.h"
 #include "vm/ArgumentsObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 struct PutArg
 {
-    PutArg(JSCompartment *comp, HeapValue *dst) : dst(dst), compartment(comp) {}
-    HeapValue *dst;
+    PutArg(JSCompartment *comp, ArgumentsObject &argsobj)
+      : compartment(comp), argsobj(argsobj), dst(argsobj.data()->slots) {}
     JSCompartment *compartment;
-    bool operator()(unsigned, Value *src) {
-        JS_ASSERT(dst->isMagic(JS_ARGS_HOLE) || dst->isUndefined());
-        if (!dst->isMagic(JS_ARGS_HOLE))
+    ArgumentsObject &argsobj;
+    HeapValue *dst;
+    bool operator()(unsigned i, Value *src) {
+        JS_ASSERT(dst->isUndefined());
+        if (!argsobj.isElementDeleted(i))
             dst->set(compartment, *src);
         ++dst;
         return true;
     }
 };
 
 void
 js_PutArgsObject(StackFrame *fp)
 {
     ArgumentsObject &argsobj = fp->argsObj();
     if (argsobj.isNormalArguments()) {
         JS_ASSERT(argsobj.maybeStackFrame() == fp);
         JSCompartment *comp = fp->scopeChain().compartment();
-        fp->forEachCanonicalActualArg(PutArg(comp, argsobj.data()->slots));
+        fp->forEachCanonicalActualArg(PutArg(comp, argsobj));
         argsobj.setStackFrame(NULL);
     } else {
         JS_ASSERT(!argsobj.maybeStackFrame());
     }
 }
 
 ArgumentsObject *
 ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
@@ -103,24 +105,30 @@ ArgumentsObject::create(JSContext *cx, u
     RootedVarShape emptyArgumentsShape(cx);
     emptyArgumentsShape =
         EmptyShape::getInitialShape(cx, clasp, proto,
                                     proto->getParent(), FINALIZE_KIND,
                                     BaseShape::INDEXED);
     if (!emptyArgumentsShape)
         return NULL;
 
-    ArgumentsData *data = (ArgumentsData *)
-        cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
+    unsigned numDeletedWords = NumWordsForBitArrayOfLength(argc);
+    unsigned numBytes = offsetof(ArgumentsData, slots) +
+                        numDeletedWords * sizeof(size_t) +
+                        argc * sizeof(Value);
+
+    ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes);
     if (!data)
         return NULL;
 
     data->callee.init(ObjectValue(callee));
     for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++)
         vp->init(UndefinedValue());
+    data->deletedBits = (size_t *)(data->slots + argc);
+    ClearAllBitArrayElements(data->deletedBits, numDeletedWords);
 
     /* We have everything needed to fill in the object, so make the object. */
     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
     if (!obj)
         return NULL;
 
     ArgumentsObject &argsobj = obj->asArguments();
 
@@ -146,43 +154,45 @@ ArgumentsObject::create(JSContext *cx, S
         return NULL;
 
     /*
      * Strict mode functions have arguments objects that copy the initial
      * actual parameter values. Non-strict mode arguments use the frame pointer
      * to retrieve up-to-date parameter values.
      */
     if (argsobj->isStrictArguments())
-        fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
+        fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj));
     else
         argsobj->setStackFrame(fp);
 
     fp->initArgsObj(*argsobj);
     return argsobj;
 }
 
 ArgumentsObject *
 ArgumentsObject::createUnexpected(JSContext *cx, StackFrame *fp)
 {
     ArgumentsObject *argsobj = create(cx, fp->numActualArgs(), fp->callee());
     if (!argsobj)
         return NULL;
 
-    fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
+    fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj));
     return argsobj;
 }
 
 static JSBool
 args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     ArgumentsObject &argsobj = obj->asArguments();
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
-        if (arg < argsobj.initialLength())
-            argsobj.setElement(arg, MagicValue(JS_ARGS_HOLE));
+        if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
+            argsobj.setElement(arg, UndefinedValue());
+            argsobj.markElementDeleted(arg);
+        }
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         argsobj.markLengthOverridden();
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
         argsobj.asNormalArguments().clearCallee();
     }
     return true;
 }
 
@@ -194,30 +204,29 @@ ArgGetter(JSContext *cx, JSObject *obj, 
 
     NormalArgumentsObject &argsobj = obj->asNormalArguments();
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         unsigned arg = unsigned(JSID_TO_INT(id));
-        if (arg < argsobj.initialLength()) {
-            JS_ASSERT(!argsobj.element(arg).isMagic(JS_ARGS_HOLE));
+        if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
             if (StackFrame *fp = argsobj.maybeStackFrame())
                 *vp = fp->canonicalActualArg(arg);
             else
                 *vp = argsobj.element(arg);
         }
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         if (!argsobj.hasOverriddenLength())
             vp->setInt32(argsobj.initialLength());
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
         const Value &v = argsobj.callee();
-        if (!v.isMagic(JS_ARGS_HOLE))
+        if (!v.isMagic(JS_OVERWRITTEN_CALLEE))
             *vp = v;
     }
     return true;
 }
 
 static JSBool
 ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
@@ -262,55 +271,67 @@ args_resolve(JSContext *cx, JSObject *ob
 {
     *objp = NULL;
 
     NormalArgumentsObject &argsobj = obj->asNormalArguments();
 
     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
-        if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
+        if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         if (argsobj.hasOverriddenLength())
             return true;
     } else {
         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
             return true;
 
-        if (argsobj.callee().isMagic(JS_ARGS_HOLE))
+        if (argsobj.callee().isMagic(JS_OVERWRITTEN_CALLEE))
             return true;
     }
 
     Value undef = UndefinedValue();
     if (!js_DefineProperty(cx, &argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
         return JS_FALSE;
 
     *objp = &argsobj;
     return true;
 }
 
 bool
 NormalArgumentsObject::optimizedGetElem(JSContext *cx, StackFrame *fp, const Value &elem, Value *vp)
 {
     JS_ASSERT(!fp->hasArgsObj());
 
+    /* Fast path: no need to convert to id when elem is already an int in range. */
     if (elem.isInt32()) {
         int32_t i = elem.toInt32();
         if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
-            *vp = fp->canonicalActualArg(elem.toInt32());
+            *vp = fp->canonicalActualArg(i);
             return true;
         }
     }
 
+    /* Slow path: create and canonicalize an id, then emulate args_resolve. */
+
     jsid id;
     if (!ValueToId(cx, elem, &id))
         return false;
+    id = js_CheckForStringIndex(id);
+
+    if (JSID_IS_INT(id)) {
+        int32_t i = JSID_TO_INT(id);
+        if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
+            *vp = fp->canonicalActualArg(i);
+            return true;
+        }
+    }
 
     if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
         *vp = Int32Value(fp->numActualArgs());
         return true;
     }
 
     if (id == ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)) {
         *vp = ObjectValue(fp->callee());
@@ -358,21 +379,18 @@ StrictArgGetter(JSContext *cx, JSObject 
     StrictArgumentsObject &argsobj = obj->asStrictArguments();
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         unsigned arg = unsigned(JSID_TO_INT(id));
-        if (arg < argsobj.initialLength()) {
-            const Value &v = argsobj.element(arg);
-            if (!v.isMagic(JS_ARGS_HOLE))
-                *vp = v;
-        }
+        if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
+            *vp = argsobj.element(arg);
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
         if (!argsobj.hasOverriddenLength())
             vp->setInt32(argsobj.initialLength());
     }
     return true;
 }
 
@@ -413,17 +431,17 @@ strictargs_resolve(JSContext *cx, JSObje
     StrictArgumentsObject &argsobj = obj->asStrictArguments();
 
     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     PropertyOp getter = StrictArgGetter;
     StrictPropertyOp setter = StrictArgSetter;
 
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
-        if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
+        if (arg >= argsobj.initialLength() || argsobj.isElementDeleted(arg))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         if (argsobj.hasOverriddenLength())
             return true;
     } else {