merge fx-team to m-c
authorPaul Rouget <paul@mozilla.com>
Wed, 25 Jul 2012 15:07:40 -0700
changeset 100412 7065b767f30db59ddce03a5275a4bbd05430f4af
parent 100411 52be83165f95fd23c85aed1ab8ea2848f2eb033d (current diff)
parent 100403 18bd0ea9e348d24d21d17e286efc1e3bf08ca65a (diff)
child 100413 c0a32cf903d83ff024242e1a64e86e7dfc7a2fa2
child 100718 966051493a76088359ce299a39719dce98dfb2fc
push id23180
push userprouget@mozilla.com
push dateWed, 25 Jul 2012 22:08:36 +0000
treeherdermozilla-central@7065b767f30d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
7065b767f30d / 17.0a1 / 20120726030603 / files
nightly linux64
7065b767f30d / 17.0a1 / 20120726030603 / files
nightly mac
7065b767f30d / 17.0a1 / 20120726030603 / files
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
merge fx-team to m-c
b2g/chrome/content/shell.js
browser/base/content/browser-sets.inc
browser/base/content/browser.xul
build/pylib/blessings/LICENSE
build/pylib/blessings/MANIFEST.in
build/pylib/blessings/PKG-INFO
build/pylib/blessings/README.rst
build/pylib/blessings/blessings/__init__.py
build/pylib/blessings/blessings/tests.py
build/pylib/blessings/setup.cfg
build/pylib/blessings/setup.py
build/pylib/blessings/tox.ini
content/base/test/header.sjs
content/base/test/test_header.html
content/events/src/nsDOMDeviceLightEvent.cpp
content/events/src/nsDOMDeviceLightEvent.h
content/events/src/nsDOMDeviceOrientationEvent.cpp
content/events/src/nsDOMDeviceOrientationEvent.h
mobile/android/chrome/content/browser.js
netwerk/test/unit/test_proxy_preservation_bug235853.js
res/drawable-hdpi/sync_fx_icon.png
res/drawable-ldpi/sync_fx_icon.png
res/drawable-mdpi/sync_fx_icon.png
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -117,21 +117,24 @@ var shell = {
     document.getElementById('shell').appendChild(browserFrame);
 
     browserFrame.contentWindow
                 .QueryInterface(Ci.nsIInterfaceRequestor)
                 .getInterface(Ci.nsIWebNavigation)
                 .sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
                                     .createInstance(Ci.nsISHistory);
 
-    ['keydown', 'keypress', 'keyup'].forEach((function listenKey(type) {
-      window.addEventListener(type, this, false, true);
-      window.addEventListener(type, this, true, true);
-    }).bind(this));
-
+    // Capture all key events so we can filter out hardware buttons
+    // And send them to Gaia via mozChromeEvents.
+    // Ideally, hardware buttons wouldn't generate key events at all, or
+    // if they did, they would use keycodes that conform to DOM 3 Events.
+    // See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=762362
+    window.addEventListener('keydown', this, true);
+    window.addEventListener('keypress', this, true);
+    window.addEventListener('keyup', this, true);
     window.addEventListener('MozApplicationManifest', this);
     window.addEventListener('mozfullscreenchange', this);
     window.addEventListener('sizemodechange', this);
     this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
 
     // Until the volume can be set from the content side, set it to a
     // a specific value when the device starts. This way the front-end
     // can display a notification when the volume change and show a volume
@@ -160,58 +163,98 @@ var shell = {
     SettingsListener.observe("debug.paint-flashing.enabled", false, function(value) {
       Services.prefs.setBoolPref("nglayout.debug.paint_flashing", value);
     });
 
     this.contentBrowser.src = homeURL;
   },
 
   stop: function shell_stop() {
-    ['keydown', 'keypress', 'keyup'].forEach((function unlistenKey(type) {
-      window.removeEventListener(type, this, false, true);
-      window.removeEventListener(type, this, true, true);
-    }).bind(this));
-
+    window.removeEventListener('keydown', this, true);
+    window.removeEventListener('keypress', this, true);
+    window.removeEventListener('keyup', this, true);
     window.removeEventListener('MozApplicationManifest', this);
     window.removeEventListener('mozfullscreenchange', this);
     window.removeEventListener('sizemodechange', this);
     this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
 
 #ifndef MOZ_WIDGET_GONK
     delete Services.audioManager;
 #endif
   },
 
-  forwardKeyToContent: function shell_forwardKeyToContent(evt) {
-    let content = shell.contentBrowser.contentWindow;
-    let generatedEvent = content.document.createEvent('KeyboardEvent');
-    generatedEvent.initKeyEvent(evt.type, true, true, evt.view, evt.ctrlKey,
-                                evt.altKey, evt.shiftKey, evt.metaKey,
-                                evt.keyCode, evt.charCode);
+  // If this key event actually represents a hardware button, filter it here
+  // and send a mozChromeEvent with detail.type set to xxx-button-press or
+  // xxx-button-release instead.
+  filterHardwareKeys: function shell_filterHardwareKeys(evt) {
+    var type;
+    switch (evt.keyCode) {
+      case evt.DOM_VK_HOME:         // Home button
+        type = 'home-button';
+        break;
+      case evt.DOM_VK_SLEEP:        // Sleep button
+        type = 'sleep-button';
+        break;
+      case evt.DOM_VK_PAGE_UP:      // Volume up button
+        type = 'volume-up-button';
+        break;
+      case evt.DOM_VK_PAGE_DOWN:    // Volume down button
+        type = 'volume-down-button';
+        break;
+      case evt.DOM_VK_ESCAPE:       // Back button (should be disabled)
+        type = 'back-button';
+        break;
+      case evt.DOM_VK_CONTEXT_MENU: // Menu button
+        type = 'menu-button';
+        break;
+      default:                      // Anything else is a real key
+        return;  // Don't filter it at all; let it propagate to Gaia
+    }
 
-    content.document.documentElement.dispatchEvent(generatedEvent);
+    // If we didn't return, then the key event represents a hardware key
+    // and we need to prevent it from propagating to Gaia
+    evt.stopImmediatePropagation();
+    evt.preventDefault(); // Prevent keypress events (when #501496 is fixed).
+
+    // If it is a key down or key up event, we send a chrome event to Gaia.
+    // If it is a keypress event we just ignore it.
+    switch (evt.type) {
+      case 'keydown':
+        type = type + '-press';
+        break;
+      case 'keyup':
+        type = type + '-release';
+        break;
+      case 'keypress':
+        return;
+    }
+  
+    // On my device, the physical hardware buttons (sleep and volume)
+    // send multiple events (press press release release), but the
+    // soft home button just sends one.  This hack is to manually
+    // "debounce" the keys. If the type of this event is the same as
+    // the type of the last one, then don't send it.  We'll never send
+    // two presses or two releases in a row.
+    // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=761067
+    if (type !== this.lastHardwareButtonEventType) {
+      this.lastHardwareButtonEventType = type;
+      this.sendChromeEvent({type: type});
+    }
   },
+  
+  lastHardwareButtonEventType: null, // property for the hack above
 
   handleEvent: function shell_handleEvent(evt) {
     let content = this.contentBrowser.contentWindow;
     switch (evt.type) {
       case 'keydown':
       case 'keyup':
       case 'keypress':
-        // Redirect the HOME key to System app and stop the applications from
-        // handling it.
-        let rootContentEvt = (evt.target.ownerDocument.defaultView == content);
-        if (!rootContentEvt && evt.eventPhase == evt.CAPTURING_PHASE &&
-            evt.keyCode == evt.DOM_VK_HOME) {
-          this.forwardKeyToContent(evt);
-          evt.preventDefault();
-          evt.stopImmediatePropagation();
-        }
+        this.filterHardwareKeys(evt);
         break;
-
       case 'mozfullscreenchange':
         // When the screen goes fullscreen make sure to set the focus to the
         // main window so noboby can prevent the ESC key to get out fullscreen
         // mode
         if (document.mozFullScreen)
           Services.fm.focusedWindow = window;
         break;
       case 'sizemodechange':
@@ -267,16 +310,19 @@ var shell = {
         }
         break;
     }
   },
   sendEvent: function shell_sendEvent(content, type, details) {
     let event = content.document.createEvent('CustomEvent');
     event.initCustomEvent(type, true, true, details ? details : {});
     content.dispatchEvent(event);
+  },
+  sendChromeEvent: function shell_sendChromeEvent(details) {
+    this.sendEvent(getContentWindow(), "mozChromeEvent", details);
   }
 };
 
 function nsBrowserAccess() {
 }
 
 nsBrowserAccess.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow]),
@@ -305,17 +351,17 @@ nsBrowserAccess.prototype = {
     return contentWindow == window;
   }
 };
 
 // Listen for system messages and relay them to Gaia.
 Services.obs.addObserver(function onSystemMessage(subject, topic, data) {
   let msg = JSON.parse(data);
   let origin = Services.io.newURI(msg.manifest, null, null).prePath;
-  shell.sendEvent(shell.contentBrowser.contentWindow, 'mozChromeEvent', {
+  shell.sendChromeEvent({
     type: 'open-app',
     url: msg.uri,
     origin: origin,
     manifest: msg.manifest
   });
 }, 'system-messages-open-app', false);
 
 (function Repl() {
@@ -410,22 +456,32 @@ var AlertsHelper = {
   },
 
   registerListener: function alert_registerListener(cookie, alertListener) {
     let id = "alert" + this._count++;
     this._listeners[id] = { observer: alertListener, cookie: cookie };
     return id;
   },
 
-  showAlertNotification: function alert_showAlertNotification(imageUrl, title, text, textClickable,
-                                                              cookie, alertListener, name) {
+  showAlertNotification: function alert_showAlertNotification(imageUrl,
+                                                              title,
+                                                              text,
+                                                              textClickable,
+                                                              cookie,
+                                                              alertListener,
+                                                              name)
+  {
     let id = this.registerListener(cookie, alertListener);
-    let content = shell.contentBrowser.contentWindow;
-    shell.sendEvent(content, "mozChromeEvent", { type: "desktop-notification", id: id, icon: imageUrl,
-                                                 title: title, text: text } );
+    shell.sendChromeEvent({
+      type: "desktop-notification",
+      id: id,
+      icon: imageUrl,
+      title: title,
+      text: text
+    });
   }
 }
 
 var WebappsHelper = {
   _installers: {},
   _count: 0,
 
   init: function webapps_init() {
@@ -451,35 +507,38 @@ var WebappsHelper = {
         break;
       case "webapps-install-denied":
         DOMApplicationRegistry.denyInstall(installer);
         break;
     }
   },
 
   observe: function webapps_observe(subject, topic, data) {
-    let content = shell.contentBrowser.contentWindow;
     let json = JSON.parse(data);
     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", {
+          shell.sendChromeEvent({
             "type": "webapps-launch",
             "url": manifest.fullLaunchPath(json.startPoint),
             "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 } );
+        shell.sendChromeEvent({
+          type: "webapps-ask-install",
+          id: id,
+          app: json.app
+        });
         break;
     }
   }
 }
 
 // Start the debugger server.
 function startDebugger() {
   if (!DebuggerServer.initialized) {
@@ -525,21 +584,33 @@ window.addEventListener('ContentStart', 
       var context = canvas.getContext('2d');
       var flags =
         context.DRAWWINDOW_DRAW_CARET |
         context.DRAWWINDOW_DRAW_VIEW |
         context.DRAWWINDOW_USE_WIDGET_LAYERS;
       context.drawWindow(window, 0, 0, width, height,
                          'rgb(255,255,255)', flags);
 
-      shell.sendEvent(content, 'mozChromeEvent', {
-          type: 'take-screenshot-success',
-          file: canvas.mozGetAsFile('screenshot', 'image/png')
+      shell.sendChromeEvent({
+        type: 'take-screenshot-success',
+        file: canvas.mozGetAsFile('screenshot', 'image/png')
       });
     } catch (e) {
       dump('exception while creating screenshot: ' + e + '\n');
-      shell.sendEvent(content, 'mozChromeEvent', {
+      shell.sendChromeEvent({
         type: 'take-screenshot-error',
         error: String(e)
       });
     }
   });
 });
+
+Services.obs.addObserver(function ContentHandler(subject, topic, data) {
+  let handler = JSON.parse(data);
+  new MozActivity({
+    name: 'view',
+    data: {
+      type: handler.type,
+      url: handler.url
+    }
+  });
+}, 'content-handler', false);
+
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -33,8 +33,13 @@ category xpcom-directory-providers brows
 # ActivitiesGlue.js
 component {70a83123-7467-4389-a309-3e81c74ad002} ActivitiesGlue.js
 contract @mozilla.org/dom/activities/ui-glue;1 {70a83123-7467-4389-a309-3e81c74ad002}
 
 # ProcessGlobal.js
 component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js
 contract @mozilla.org/b2g-process-global;1 {1a94c87a-5ece-4d11-91e1-d29c29f21b28}
 category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1
+
+# ContentHandler.js
+component {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} ContentHandler.js
+contract @mozilla.org/uriloader/content-handler;1?type=application/pdf {d18d0216-d50c-11e1-ba54-efb18d0ef0ac}
+
new file mode 100644
--- /dev/null
+++ b/b2g/components/ContentHandler.js
@@ -0,0 +1,48 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+
+const PDF_CONTENT_TYPE = "application/pdf";
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+function log(aMsg) {
+  let msg = "ContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg);
+  Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
+                                     .logStringMessage(msg);
+  dump(msg + "\n");
+}
+
+const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
+function ContentHandler() {
+}
+
+ContentHandler.prototype = {
+  handleContent: function handleContent(aMimetype, aContext, aRequest) {
+    if (aMimetype != PDF_CONTENT_TYPE)
+      throw NS_ERROR_WONT_HANDLE_CONTENT;
+
+    if (!(aRequest instanceof Ci.nsIChannel))
+      throw NS_ERROR_WONT_HANDLE_CONTENT;
+
+    let detail = {
+      "type": aMimetype,
+      "url": aRequest.URI.spec
+    };
+    Services.obs.notifyObservers(this, "content-handler", JSON.stringify(detail)); 
+
+    aRequest.cancel(Cr.NS_BINDING_ABORTED);
+  },
+
+  classID: Components.ID("{d18d0216-d50c-11e1-ba54-efb18d0ef0ac}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler])
+};
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentHandler]);
--- a/b2g/components/DirectoryProvider.js
+++ b/b2g/components/DirectoryProvider.js
@@ -17,17 +17,17 @@ function DirectoryProvider() {
 
 DirectoryProvider.prototype = {
   classID: Components.ID("{9181eb7c-6f87-11e1-90b1-4f59d80dd2e5}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
 
   getFile: function dp_getFile(prop, persistent) {
 #ifdef MOZ_WIDGET_GONK
-    let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir"];
+    let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir", "permissionDBPDir"];
     if (localProps.indexOf(prop) != -1) {
       prop.persistent = true;
       let file = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile)
       file.initWithPath(LOCAL_DIR);
       return file;
     }
 #endif
--- a/b2g/components/Makefile.in
+++ b/b2g/components/Makefile.in
@@ -12,23 +12,24 @@ include $(DEPTH)/config/autoconf.mk
 MODULE = B2GComponents
 XPIDL_MODULE = B2GComponents
 
 XPIDLSRCS = \
         b2g.idl \
         $(NULL)
 
 EXTRA_PP_COMPONENTS = \
+        ActivitiesGlue.js \
         AlertsService.js \
         B2GComponents.manifest \
         CameraContent.js \
+        ContentHandler.js \
         ContentPermissionPrompt.js \
         DirectoryProvider.js \
         MozKeyboard.js \
         ProcessGlobal.js \
-        ActivitiesGlue.js \
         $(NULL)
 
 ifdef MOZ_UPDATER
 EXTRA_PP_COMPONENTS += UpdatePrompt.js
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -679,8 +679,9 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 @BINPATH@/components/ContentPermissionPrompt.js
 #ifdef MOZ_UPDATER
 @BINPATH@/components/UpdatePrompt.js
 #endif
 @BINPATH@/components/MozKeyboard.js
 @BINPATH@/components/DirectoryProvider.js
 @BINPATH@/components/ActivitiesGlue.js
 @BINPATH@/components/ProcessGlobal.js
+@BINPATH@/components/ContentHandler.js
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -38,22 +38,36 @@
 
 #include "mozilla/Telemetry.h"
 
 static void Output(const char *fmt, ... )
 {
   va_list ap;
   va_start(ap, fmt);
 
-#if defined(XP_WIN) && !MOZ_WINCONSOLE
-  PRUnichar msg[2048];
-  _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap);
-  MessageBoxW(NULL, msg, L"XULRunner", MB_OK | MB_ICONERROR);
+#ifndef XP_WIN
+  vfprintf(stderr, fmt, ap);
 #else
-  vfprintf(stderr, fmt, ap);
+  char msg[2048];
+  vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
+
+  wchar_t wide_msg[2048];
+  MultiByteToWideChar(CP_UTF8,
+                      0,
+                      msg,
+                      -1,
+                      wide_msg,
+                      _countof(wide_msg));
+#if MOZ_WINCONSOLE
+  fwprintf_s(stderr, wide_msg);
+#else
+  MessageBoxW(NULL, wide_msg, L"Firefox", MB_OK
+                                        | MB_ICONERROR
+                                        | MB_SETFOREGROUND);
+#endif
 #endif
 
   va_end(ap);
 }
 
 /**
  * Return true if |arg| matches the given argument name.
  */
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1181,8 +1181,10 @@ pref("pdfjs.previousHandler.alwaysAskBef
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 // (This is intentionally on the high side; see bug 746055.)
 pref("image.mem.max_decoded_image_kb", 256000);
 
 // Example social provider
 pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com\",\"name\":\"MoTown\",\"workerURL\":\"https://motown-dev.mozillalabs.com/social/worker.js\",\"iconURL\":\"https://motown-dev.mozillalabs.com/images/motown-icon.png\",\"sidebarURL\":\"https://motown-dev.mozillalabs.com/social/sidebar\"}");
 pref("social.sidebar.open", true);
+pref("browser.social.whitelist", "");
+pref("social.active", false);
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -327,16 +327,20 @@
                 key="key_openAddons"/>
       <splitmenu id="appmenu_customize"
 #ifdef XP_UNIX
                  label="&preferencesCmdUnix.label;"
 #else
                  label="&preferencesCmd2.label;"
 #endif
                  oncommand="openPreferences();">
+          <menuitem id="appmenu_socialToggle"
+                    type="checkbox"
+                    autocheck="false"
+                    command="Social:Toggle"/>
           <menupopup id="appmenu_customizeMenu"
                      onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('appmenu_toggleToolbarsSeparator'));">
             <menuitem id="appmenu_preferences"
 #ifdef XP_UNIX
                       label="&preferencesCmdUnix.label;"
 #else
                       label="&preferencesCmd2.label;"
 #endif
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -491,16 +491,20 @@
                         accesskey="&downloads.accesskey;"
                         key="key_openDownloads"
                         command="Tools:Downloads"/>
               <menuitem id="menu_openAddons"
                         label="&addons.label;"
                         accesskey="&addons.accesskey;"
                         key="key_openAddons"
                         command="Tools:Addons"/>
+              <menuitem id="menu_socialToggle"
+                        type="checkbox"
+                        autocheck="false"
+                        command="Social:Toggle"/>
 #ifdef MOZ_SERVICES_SYNC
               <!-- only one of sync-setup or sync-menu will be showing at once -->
               <menuitem id="sync-setup"
                         label="&syncSetup.label;"
                         accesskey="&syncSetup.accesskey;"
                         observes="sync-setup-state"
                         oncommand="gSyncUI.openSetup()"/>
               <menuitem id="sync-syncnowitem"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -104,16 +104,17 @@
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();"/>
     <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
     <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
+    <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
   </commandset>
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
              oncommand="PlacesCommandHook.showPlacesOrganizer('AllBookmarks');"/>
     <command id="Browser:ShowAllHistory"
              oncommand="PlacesCommandHook.showPlacesOrganizer('History');"/>
   </commandset>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -6,16 +6,18 @@ let SocialUI = {
   // Called on delayed startup to initialize UI
   init: function SocialUI_init() {
     Services.obs.addObserver(this, "social:pref-changed", false);
     Services.obs.addObserver(this, "social:ambient-notification-changed", false);
     Services.obs.addObserver(this, "social:profile-changed", false);
 
     Services.prefs.addObserver("social.sidebar.open", this, false);
 
+    gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler, true, true);
+
     Social.init(this._providerReady.bind(this));
   },
 
   // Called on window unload
   uninit: function SocialUI_uninit() {
     Services.obs.removeObserver(this, "social:pref-changed");
     Services.obs.removeObserver(this, "social:ambient-notification-changed");
     Services.obs.removeObserver(this, "social:profile-changed");
@@ -26,36 +28,129 @@ let SocialUI = {
   showProfile: function SocialUI_showProfile() {
     if (Social.provider)
       openUILink(Social.provider.profile.profileURL);
   },
 
   observe: function SocialUI_observe(subject, topic, data) {
     switch (topic) {
       case "social:pref-changed":
+        this.updateToggleCommand();
         SocialShareButton.updateButtonHiddenState();
         SocialToolbar.updateButtonHiddenState();
         SocialSidebar.updateSidebar();
         break;
       case "social:ambient-notification-changed":
         SocialToolbar.updateButton();
         break;
       case "social:profile-changed":
         SocialToolbar.updateProfile();
         break;
       case "nsPref:changed":
         SocialSidebar.updateSidebar();
     }
   },
 
+  get toggleCommand() {
+    return document.getElementById("Social:Toggle");
+  },
+
   // Called once Social.jsm's provider has been set
   _providerReady: function SocialUI_providerReady() {
+    // If we couldn't find a provider, nothing to do here.
+    if (!Social.provider)
+      return;
+
+    this.updateToggleCommand();
+
+    let toggleCommand = this.toggleCommand;
+    let label = gNavigatorBundle.getFormattedString("social.enable.label",
+                                                    [Social.provider.name]);
+    let accesskey = gNavigatorBundle.getString("social.enable.accesskey");
+    toggleCommand.setAttribute("label", label);
+    toggleCommand.setAttribute("accesskey", accesskey);
+
     SocialToolbar.init();
     SocialShareButton.init();
     SocialSidebar.init();
+  },
+
+  updateToggleCommand: function SocialUI_updateToggleCommand() {
+    let toggleCommand = this.toggleCommand;
+    toggleCommand.setAttribute("checked", Social.enabled);
+
+    // FIXME: bug 772808: menu items don't inherit the "hidden" state properly,
+    // need to update them manually.
+    // This should just be: toggleCommand.hidden = !Social.active;
+    for (let id of ["appmenu_socialToggle", "menu_socialToggle"]) {
+      let el = document.getElementById(id);
+      if (!el)
+        continue;
+
+      if (Social.active)
+        el.removeAttribute("hidden");
+      else
+        el.setAttribute("hidden", "true");
+    }
+  },
+
+  // This handles "ActivateSocialFeature" events fired against content documents
+  // in this window.
+  _activationEventHandler: function SocialUI_activationHandler(e) {
+    // Nothing to do if Social is already active, or we don't have a provider
+    // to enable yet.
+    if (Social.active || !Social.provider)
+      return;
+
+    let targetDoc = e.target;
+
+    // Event must be fired against the document
+    if (!(targetDoc instanceof HTMLDocument))
+      return;
+
+    // Ignore events fired in background tabs
+    if (targetDoc.defaultView.top != content)
+      return;
+
+    // Check that the associated document's origin is in our whitelist
+    let prePath = targetDoc.documentURIObject.prePath;
+    let whitelist = Services.prefs.getCharPref("browser.social.whitelist");
+    if (whitelist.split(",").indexOf(prePath) == -1)
+      return;
+
+    // If the last event was received < 1s ago, ignore this one
+    let now = Date.now();
+    if (now - Social.lastEventReceived < 1000)
+      return;
+    Social.lastEventReceived = now;
+
+    // Enable the social functionality, and indicate that it was activated
+    Social.active = true;
+
+    // Show a warning, allow undoing the activation
+    let description = document.getElementById("social-activation-message");
+    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
+    let message = gNavigatorBundle.getFormattedString("social.activated.message",
+                                                      [Social.provider.name, brandShortName]);
+    description.value = message;
+
+    SocialUI.notificationPanel.hidden = false;
+
+    setTimeout(function () {
+      SocialUI.notificationPanel.openPopup(SocialToolbar.button, "bottomcenter topright");
+    }.bind(this), 0);
+  },
+
+  get notificationPanel() {
+    return document.getElementById("socialActivatedNotification")
+  },
+
+  undoActivation: function SocialUI_undoActivation() {
+    Social.active = false;
+    this.notificationPanel.hidePopup();
   }
 }
 
 let SocialShareButton = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SSB_init() {
     this.updateButtonHiddenState();
 
@@ -148,32 +243,43 @@ let SocialShareButton = {
     }
   }
 };
 
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialToolbar_init() {
     document.getElementById("social-provider-image").setAttribute("image", Social.provider.iconURL);
-    
-    // handle button state
-    document.getElementById("social-statusarea-popup").addEventListener("popupshowing", function(e) {
-      document.getElementById("social-toolbar-button").setAttribute("open", "true");
-    }, false);
-    document.getElementById("social-statusarea-popup").addEventListener("popuphiding", function(e) {
-      document.getElementById("social-toolbar-button").removeAttribute("open");
-    }, false);
+
+    let removeItem = document.getElementById("social-remove-menuitem");
+    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
+    let label = gNavigatorBundle.getFormattedString("social.remove.label",
+                                                    [brandShortName]);
+    let accesskey = gNavigatorBundle.getString("social.remove.accesskey");
+    removeItem.setAttribute("label", label);
+    removeItem.setAttribute("accesskey", accesskey);
+
+    let statusAreaPopup = document.getElementById("social-statusarea-popup");
+    statusAreaPopup.addEventListener("popupshowing", function(e) {
+      this.button.setAttribute("open", "true");
+    }.bind(this));
+    statusAreaPopup.addEventListener("popuphidden", function(e) {
+      this.button.removeAttribute("open");
+    }.bind(this));
 
     this.updateButton();
     this.updateProfile();
   },
 
+  get button() {
+    return document.getElementById("social-toolbar-button");
+  },
+
   updateButtonHiddenState: function SocialToolbar_updateButtonHiddenState() {
-    let toolbarbutton = document.getElementById("social-toolbar-button");
-    toolbarbutton.hidden = !Social.uiVisible;
+    this.button.hidden = !Social.uiVisible;
   },
 
   updateProfile: function SocialToolbar_updateProfile() {
     // Profile may not have been initialized yet, since it depends on a worker
     // response. In that case we'll be called again when it's available, via
     // social:profile-changed
     let profile = Social.provider.profile || {};
     let userPortrait = profile.portrait || "chrome://browser/skin/social/social.png";
@@ -228,20 +334,20 @@ var SocialToolbar = {
   showAmbientPopup: function SocialToolbar_showAmbientPopup(iconContainer) {
     let iconImage = iconContainer.firstChild;
     let panel = document.getElementById("social-notification-panel");
     let notifBrowser = document.getElementById("social-notification-browser");
 
     panel.hidden = false;
 
     function sizePanelToContent() {
-      // XXX Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
-      // XXX need to handle dynamic sizing
+      // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
+      // Need to handle dynamic sizing
       let doc = notifBrowser.contentDocument;
-      // XXX "notif" is an implementation detail that we should get rid of
+      // "notif" is an implementation detail that we should get rid of
       // eventually
       let body = doc.getElementById("notif") || doc.body.firstChild;
       if (!body)
         return;
       let h = body.scrollHeight > 0 ? body.scrollHeight : 300;
       notifBrowser.style.width = body.scrollWidth + "px";
       notifBrowser.style.height = h + "px";
     }
@@ -249,23 +355,23 @@ var SocialToolbar = {
     notifBrowser.addEventListener("DOMContentLoaded", function onload() {
       notifBrowser.removeEventListener("DOMContentLoaded", onload);
       sizePanelToContent();
     });
 
     panel.addEventListener("popuphiding", function onpopuphiding() {
       panel.removeEventListener("popuphiding", onpopuphiding);
       // unload the panel
-      document.getElementById("social-toolbar-button").removeAttribute("open");
+      SocialToolbar.button.removeAttribute("open");
       notifBrowser.setAttribute("src", "about:blank");
     });
 
     notifBrowser.setAttribute("origin", Social.provider.origin);
     notifBrowser.setAttribute("src", iconImage.getAttribute("contentPanel"));
-    document.getElementById("social-toolbar-button").setAttribute("open", "true");
+    this.button.setAttribute("open", "true");
     panel.openPopup(iconImage, "bottomcenter topleft", 0, 0, false, false);
   }
 }
 
 var SocialSidebar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialSidebar_init() {
     this.updateSidebar();
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -177,16 +177,54 @@
                 class="editBookmarkPanelBottomButton"
                 label="&editBookmark.done.label;"
                 default="true"
                 oncommand="StarUI.panel.hidePopup();"/>
 #endif
       </hbox>
     </panel>
 
+    <panel id="socialActivatedNotification"
+           type="arrow"
+           hidden="true"
+           consumeoutsideclicks="true"
+           align="start"
+           role="alert">
+      <hbox flex="1">
+        <image src="chrome://browser/content/social-icon.png" class="popup-notification-icon"/>
+        <vbox flex="1">
+          <description id="social-activation-message" class="popup-notification-description"/>
+          <spacer flex="1"/>
+          <hbox pack="end" align="center" class="popup-notification-button-container">
+#ifdef XP_UNIX
+        <button id="social-undoactivation-button"
+                label="&social.activated.button.label;"
+                accesskey="&social.activated.button.accesskey;"
+                onclick="SocialUI.undoActivation();"/>
+        <button default="true"
+                autofocus="autofocus"
+                label="&social.ok.label;"
+                accesskey="&social.ok.accesskey;"
+                oncommand="SocialUI.notificationPanel.hidePopup();"/>
+#else
+        <button default="true"
+                autofocus="autofocus"
+                label="&social.ok.label;"
+                accesskey="&social.ok.accesskey;"
+                oncommand="SocialUI.notificationPanel.hidePopup();"/>
+        <button id="social-undoactivation-button"
+                label="&social.activated.button.label;"
+                accesskey="&social.activated.button.accesskey;"
+                onclick="SocialUI.undoActivation();"/>
+#endif
+          </hbox>
+        </vbox>
+      </hbox>
+    </panel>
+
     <panel id="editSharePopup"
            type="arrow"
            orient="vertical"
            ignorekeys="true"
            hidden="true"
            onpopupshown="SocialShareButton.panelShown(event);"
            consumeoutsideclicks="true"
            level="top">
@@ -209,26 +247,26 @@
                 class="editSharePopupBottomButton"
                 label="&social.sharePopup.undo.label;"
                 accesskey="&social.sharePopup.undo.accesskey;"
                 command="Social:UnsharePage"/>
         <button id="editSharePopupOkButton"
                 class="editSharePopupBottomButton"
                 default="true"
                 autofocus="autofocus"
-                label="&social.sharePopup.ok.label;"
-                accesskey="&social.sharePopup.ok.accesskey;"
+                label="&social.ok.label;"
+                accesskey="&social.ok.accesskey;"
                 oncommand="SocialShareButton.dismissSharePopup();"/>
 #else
         <button id="editSharePopupOkButton"
                 class="editSharePopupBottomButton"
                 default="true"
                 autofocus="autofocus"
-                label="&social.sharePopup.ok.label;"
-                accesskey="&social.sharePopup.ok.accesskey;"
+                label="&social.ok.label;"
+                accesskey="&social.ok.accesskey;"
                 oncommand="SocialShareButton.dismissSharePopup();"/>
         <button id="editSharePopupUndoButton"
                 class="editSharePopupBottomButton"
                 label="&social.sharePopup.undo.label;"
                 accesskey="&social.sharePopup.undo.accesskey;"
                 command="Social:UnsharePage"/>
 #endif
       </hbox>
@@ -633,16 +671,18 @@
                 <image id="social-statusarea-user-portrait"/>
                 <vbox>
                   <label id="social-statusarea-notloggedin"
                          value="&social.notLoggedIn.label;"/>
                   <button id="social-statusarea-username"
                           oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"/>
                 </vbox>
               </hbox>
+              <menuitem id="social-remove-menuitem"
+                        oncommand="Social.active = false;"/>
               <menuitem id="social-toggle-sidebar-menuitem"
                         type="checkbox"
                         autocheck="false"
                         command="Social:ToggleSidebar"
                         label="&social.toggleSidebar.label;"
                         accesskey="&social.toggleSidebar.accesskey;"/>
             </menupopup>
           </button>
new file mode 100644
index 0000000000000000000000000000000000000000..37e54a1e9a0637be9a078eb4e51465eb609a3174
GIT binary patch
literal 2166
zc$|G!X;f3!8VyLO$O9r!A6UiPFqA$d6Cg<>Ku8#Z#3DoqwhS3=NPr9^mym!1ASe`4
z1{IkVtEC1-5FZY>Bmn_Ir7A@M6~Q7P3RtIywn7sX-&=1jd)B@8obOwEe`lZX>>oEb
zbYq~|vX#qVFqj!Fh#IDwt@ZCxW8GJkyV^`Q*+TwIC|t~gQdm+DM&^pyAV3qc;=nMF
z#Z@MCgI+M$5~P5^gqZXYB1bGlvGf>}LMVahhnJ5+!r~-=5WoiG1R@f0wxtyb2)HC<
zga;i%mry{yAShJ|hNo_1a8eUE1TNCY8}L#Pbp?bV!~zt;M3IcBAR*t?CF<7tG#UxK
zgFp!+<a<#}dMH2<OF_T`g>mIz)?t8kSQOUH-P6-^Er7#dF=z}9jm5cQJ&A5OA_fC|
z7)af2QZA1eMh*C|mo6e9`4A)_qR}ZSDX0`Tlvo;v#u5kweGMGWRflkuDMb)V;VP2Z
zFIJ#}GLBRrfdpa^ppRK>aWX_gA{UP!lzc2Jl6`2Cu3=~eOM=FtFzEjQ(&>K>6$(G1
zWl$K%`+KyEp_G8=Fi<8=mU46#$FtXyB}9r8WI<vnLo7~Q>|!Wi42flYu>_!mdjND6
zM<CM2@9=awktUKsED;B!QAtQ$1|<-1iFkJpcYimWpPxI{AFF%(+^7Vyo4-58k4&Ki
zV6lr_s+f~31Vzvym-}BX<&#{!72dN!sXz{L1EgXh@b1V&!KbwlKCR_Fm-}fg<WF+Z
zIx*<~yXeJ~&OQ3&N89RxkH!Z@I=4%8wywTE2f$!PQ#2}>p%~h>IU&&+v?e_tsu~=e
zP81xFM+RT{F+FyJA~J)Gh5zH%tq)3!)y>QO9USIEY5RiOEtFaO2Nv2(&c;iAW|}w~
z9Al`zL|DOx!v1|U^iAv^LpP`8Ynqzenueq7eH8eeJe;gm_RG2d++81nEYh^sH{VKl
z9kVkzaXY84<EH3-Xmlp4XrfHf!tH+WQ%{fD$~3R!H0jAInNO@U-l>0jo4BiHcE>P|
zcW|cdNLhLxoT&ip-~s1r<`(Q+U0(b;tFF7V*C(xaI?!<V(c|u|P0bfBCWn4KUP7{{
z?aOuU@&%QpD-5<&7!5nwUk#I7IVt(hd)?F5^HmkMBU+(12AbjOndAHGstNa4RjqvO
zGaTMggIb=mIbAEYxn+AgVeM|b0pi5SerPg-HKO_AcTU=w2;p(%>oJl>n=zkX8(b|q
z`)He#%(@Y8v(;#~psnXr(B2c0IQ&RAq#0A5&a$bzjmK<pG1`>5PV(7Z?Fmjq?<(}a
zDq9<>V06ajEq3$GyH0jTMQ6kU>4iVFAE7!GeS=9?aj+`igQfdb$3*ZdHGI!5YG9sL
z`_yLP#PXx_oqc9z6Fui19QN;+-4V9HdZUgQ@O8*9G%39la;Ut~;Wny}%O1~*KkJP*
zFRM0n8Z4sZmd^%gs6q5`E)+F~-Pv)s@*tjMcYiRxJBFL|3w7Xnqr<ma_XAdxBrA2b
zZ@%-?KG;6ZnBsIn*60Y_%X`p(+<ya$GdHDS+pqzXEtU@%dzA|_Pc}#L%B^_Rj`@jY
z4JqL!@g=>QCOE;lw9>qQlBr30y2%jH-g{_SL3k(QKz{Xl#^F#SC;X-P_y>gEl4eR(
zxH?A;PhxAc7>c}SvFX`qnPx7gUd%Ii3pA=C!)s5@nxVHrOINvvVcLJAA}uMkVxw)v
z4^>yz)?H?6xRyD=NZ?M8-_jK&+R+VBb7OviJz>dlcfylhON$MHxVF!JQ<dfpC#|+c
z!Hes6sXA&N8+Y|qc)VR{xC8-~O>xQc@_oghf2l;ZP+!qTLcT#5AA1=H6=F>oSsNR-
z7vXIpGgZOIRiBMEm>9^Tl!G)VDx23-3+of!vaa*Byv}kowJinm3gO113MBk8lcsV;
zmX06}2SoCFM_aPn{;cFRx3$ba;p{%?zvfZxRXKMk%Q|)dmhs$(-RAddbn+hm)Ysf`
zd<GVZ$o0L<jqP+k`#6Q6borsl+>vyCyX=}>rI&BhcsjX>h`5PxJVg6G2ftdvT%cQq
z7&?9N6~blfief$)&yH=Fwz%2@)~D93s}BBw5br5|%@dZ$S4|X*{5;nAy;T(-*t7H1
zgpIj}MdnKLos2+CcUEoEk?a~KK1aU(d_{%!J0JCq)Tck5IF(p%?_2ZvQSwpfWx1Q{
z^9vg`MVrRC=lh0i*e+Y1(-pj>W+3{S(Pl(hulptA)Eh5LJmq7WnW?EE`d4<$m|br#
zzA)?Wk8#HmK5sJ>Bk$~oM}=z(T|4=a1GdJ7^xP2e_xthflNWFI+ouf=HZ;onjs>Ea
z_I7dJ1836ibiItbKXWCfBrn@h(o!30MU|Y-V6|FI9hH^d9J;<kGFvYMA74-{v@|ZX
zy!j&)H~G&I;oL*^;I*2@bL1t06;pBb$mHXZoBn)TcT)IT%5F}3F)v$Kih-r8P1}o8
SO``RG0yO`P)Ox?z%)bDuBY(vJ
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -253,16 +253,20 @@ endif
                  browser_aboutSyncProgress.js \
                  browser_middleMouse_inherit.js \
                  redirect_bug623155.sjs \
                  browser_tabDrop.js \
                  browser_lastAccessedTab.js \
                  browser_bug734076.js \
                  browser_social_toolbar.js \
                  browser_social_sidebar.js \
+                 browser_social_mozSocial_API.js \
+                 social_panel.html \
+                 social_sidebar.html \
+                 social_worker.js \
                  $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
 		browser_bug462289.js \
 		$(NULL)
 else
 _BROWSER_FILES += \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_social_mozSocial_API.js
@@ -0,0 +1,87 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+
+function test() {
+  // XXX Bug 775779
+  if (Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2).isDebugBuild) {
+    ok(true, "can't run social sidebar test in debug builds because they falsely report leaks");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  let manifest = { // normal provider
+    name: "provider 1",
+    origin: "http://example.com",
+    sidebarURL: "http://example.com/browser/browser/base/content/test/social_sidebar.html",
+    workerURL: "http://example.com/browser/browser/base/content/test/social_worker.js",
+    iconURL: "chrome://branding/content/icon48.png"
+  };
+  runSocialTestWithProvider(manifest, doTest);
+}
+
+function doTest() {
+  let iconsReady = false;
+  let gotSidebarMessage = false;
+
+  function checkNext() {
+    if (iconsReady && gotSidebarMessage)
+      triggerIconPanel();
+  }
+
+  function triggerIconPanel() {
+    let statusIcons = document.getElementById("social-status-iconbox");
+    ok(!statusIcons.firstChild.collapsed, "status icon is visible");
+    // Click the button to trigger its contentPanel
+    let panel = document.getElementById("social-notification-panel");
+    EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
+  }
+
+  let port = Social.provider.port;
+  ok(port, "provider has a port");
+  port.postMessage({topic: "test-init"});
+  Social.provider.port.onmessage = function (e) {
+    let topic = e.data.topic;
+    switch (topic) {
+      case "got-panel-message":
+        ok(true, "got panel message");
+        // Wait for the panel to close before ending the test
+        let panel = document.getElementById("social-notification-panel");
+        panel.addEventListener("popuphidden", function hiddenListener() {
+          panel.removeEventListener("popuphidden", hiddenListener);
+          SocialService.removeProvider(Social.provider.origin, finish);
+        });
+        panel.hidePopup();
+        break;
+      case "got-sidebar-message":
+        // The sidebar message will always come first, since it loads by default
+        ok(true, "got sidebar message");
+        info(topic);
+        gotSidebarMessage = true;
+        checkNext();
+        break;
+    }
+  }
+
+  // Our worker sets up ambient notification at the same time as it responds to
+  // the workerAPI initialization. If it's already initialized, we can
+  // immediately check the icons, otherwise wait for initialization by
+  // observing the topic sent out by the social service.
+  if (Social.provider.workerAPI.initialized) {
+    iconsReady = true;
+    checkNext();
+  } else {
+    Services.obs.addObserver(function obs() {
+      Services.obs.removeObserver(obs, "social:ambient-notification-changed");
+      // Let the other observers (like the one that updates the UI) run before
+      // checking the icons.
+      executeSoon(function () {
+        iconsReady = true;
+        checkNext();
+      });
+    }, "social:ambient-notification-changed", false);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social_panel.html
@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <meta charset="utf-8">
+    <script>
+      function pingWorker() {
+        var port = navigator.mozSocial.getWorker().port;
+        port.postMessage({topic: "panel-message", result: "ok"});
+      }
+    </script>
+  </head>
+  <body onload="pingWorker();">
+    <p>This is a test social panel.</p>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social_sidebar.html
@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <meta charset="utf-8">
+    <script>
+      function pingWorker() {
+        var port = navigator.mozSocial.getWorker().port;
+        port.postMessage({topic: "sidebar-message", result: "ok"});
+      }
+    </script>
+  </head>
+  <body onload="pingWorker();">
+    <p>This is a test social sidebar.</p>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social_worker.js
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+let testPort;
+
+onconnect = function(e) {
+  let port = e.ports[0];
+  port.onmessage = function onMessage(event) {
+    let topic = event.data.topic;
+    switch (topic) {
+      case "test-init":
+        testPort = port;
+        break;
+      case "sidebar-message":
+        if (testPort && event.data.result == "ok")
+          testPort.postMessage({topic:"got-sidebar-message"});
+        break;
+      case "panel-message":
+        if (testPort && event.data.result == "ok")
+          testPort.postMessage({topic:"got-panel-message"});
+        break;
+      case "social.initialize":
+        // This is the workerAPI port, respond and set up a notification icon.
+        port.postMessage({topic: "social.initialize-response"});
+        let profile = {
+          userName: "foo"
+        };
+        port.postMessage({topic: "social.user-profile", data: profile});
+        let icon = {
+          name: "testIcon",
+          iconURL: "chrome://branding/content/icon48.png",
+          contentPanel: "http://example.com/browser/browser/base/content/test/social_panel.html",
+          counter: 1
+        };
+        port.postMessage({topic: "social.ambient-notification", data: icon});
+        break;
+    }
+  }
+}
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -96,11 +96,12 @@ browser.jar:
 *       content/browser/downloadManagerOverlay.xul    (content/downloadManagerOverlay.xul)
 *       content/browser/jsConsoleOverlay.xul          (content/jsConsoleOverlay.xul)
 *       content/browser/softwareUpdateOverlay.xul  (content/softwareUpdateOverlay.xul)
 #endif
 *       content/browser/viewSourceOverlay.xul         (content/viewSourceOverlay.xul)
 #ifdef XP_WIN
 *       content/browser/win6BrowserOverlay.xul        (content/win6BrowserOverlay.xul)
 #endif
+        content/browser/social-icon.png               (content/social-icon.png)
 # the following files are browser-specific overrides
 *       content/browser/license.html                  (/toolkit/content/license.html)
 % override chrome://global/content/license.html chrome://browser/content/license.html
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -63,17 +63,17 @@ PlacesViewBase.prototype = {
 
     if (this._rootElt.localName == "menupopup")
       this._rootElt._built = false;
 
     this._result = val;
     if (val) {
       this._resultNode = val.root;
       this._rootElt._placesNode = this._resultNode;
-      this._domNodes = new WeakMap();
+      this._domNodes = new Map();
       this._domNodes.set(this._resultNode, this._rootElt);
 
       // This calls _rebuild through invalidateContainer.
       this._resultNode.containerOpen = true;
     }
     else {
       this._resultNode = null;
       delete this._domNodes;
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -75,17 +75,17 @@ function PlacesController(aView) {
   this._view = aView;
   XPCOMUtils.defineLazyServiceGetter(this, "clipboard",
                                      "@mozilla.org/widget/clipboard;1",
                                      "nsIClipboard");
   XPCOMUtils.defineLazyGetter(this, "profileName", function () {
     return Services.dirsvc.get("ProfD", Ci.nsIFile).leafName;
   });
 
-  this._cachedLivemarkInfoObjects = new WeakMap();
+  this._cachedLivemarkInfoObjects = new Map();
 }
 
 PlacesController.prototype = {
   /**
    * The places view.
    */
   _view: null,
 
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -46,17 +46,17 @@ PlacesTreeView.prototype = {
     return this.__dateService;
   },
 
   QueryInterface: XPCOMUtils.generateQI(PTV_interfaces),
 
   // Bug 761494:
   // ----------
   // Some addons use methods from nsINavHistoryResultObserver and
-  // nsINavHistoryResultTreeViewer, without QIing to these intefaces first.
+  // nsINavHistoryResultTreeViewer, without QIing to these interfaces first.
   // That's not a problem when the view is retrieved through the
   // <tree>.view getter (which returns the wrappedJSObject of this object),
   // it raises an issue when the view retrieved through the treeBoxObject.view
   // getter.  Thus, to avoid breaking addons, the interfaces are prefetched.
   classInfo: XPCOMUtils.generateCI({ interfaces: PTV_interfaces }),
 
   /**
    * This is called once both the result and the tree are set.
@@ -148,22 +148,31 @@ PlacesTreeView.prototype = {
    * container, this method will just return a calculated row value, without
    * making assumptions on existence of the node at that position.
    * @return aNode's row if it's in the rows list or if aForceBuild is set, -1
    *         otherwise.
    */
   _getRowForNode:
   function PTV__getRowForNode(aNode, aForceBuild, aParentRow, aNodeIndex) {
     if (aNode == this._rootNode)
-      throw "The root node is never visible";
+      throw new Error("The root node is never visible");
 
-    let ancestors = PlacesUtils.nodeAncestors(aNode);
-    for (let ancestor in ancestors) {
+    // A node is removed form the view either if it has no parent or if its
+    // root-ancestor is not the root node (in which case that's the node
+    // for which nodeRemoved was called).
+    let ancestors = [x for each (x in PlacesUtils.nodeAncestors(aNode))];
+    if (ancestors.length == 0 ||
+        ancestors[ancestors.length - 1] != this._rootNode) {
+      throw new Error("Removed node passed to _getRowForNode");
+    }
+
+    // Ensure that the entire chain is open, otherwise that node is invisible.
+    for (let ancestor of ancestors) {
       if (!ancestor.containerOpen)
-        throw "Invisible node passed to _getRowForNode";
+        throw new Error("Invisible node passed to _getRowForNode");
     }
 
     // Non-plain containers are initially built with their contents.
     let parent = aNode.parent;
     let parentIsPlain = this._isPlainContainer(parent);
     if (!parentIsPlain) {
       if (parent == this._rootNode)
         return this._rows.indexOf(aNode);
@@ -1092,17 +1101,17 @@ PlacesTreeView.prototype = {
     if (this._result) {
       this._result.removeObserver(this);
       this._rootNode.containerOpen = false;
     }
 
     if (val) {
       this._result = val;
       this._rootNode = this._result.root;
-      this._cellProperties = new WeakMap();
+      this._cellProperties = new Map();
       this._cuttingNodes = new Set();
     }
     else if (this._result) {
       delete this._result;
       delete this._rootNode;
       delete this._cellProperties;
       delete this._cuttingNodes;
     }
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -652,16 +652,26 @@ doesn't display any label, but exposes a
 <!ENTITY markupButton.arialabel          "Markup">
 <!-- LOCALIZATION NOTE (markupButton.accesskey): The key bound to the Markup panel's
 toolbar button -->
 <!ENTITY markupButton.accesskey          "M">
 
 <!ENTITY socialToolbar.title        "Social Toolbar Button">
 <!ENTITY social.notLoggedIn.label   "Not logged in">
 
+<!-- LOCALIZATION NOTE (social.ok.label, social.ok.accesskey): this string is
+     used for the "OK" button for two different social panels. One appears when
+     the feature is activated (social.activated.* below), and the other when
+     the user clicks the "Share" button a second time (social.sharePopup.*
+     below). -->
+<!ENTITY social.ok.label       "OK">
+<!ENTITY social.ok.accesskey   "O">
+
 <!ENTITY social.sharePopup.undo.label     "Unshare">
 <!ENTITY social.sharePopup.undo.accesskey "U">
-<!ENTITY social.sharePopup.ok.label       "OK">
-<!ENTITY social.sharePopup.ok.accesskey   "O">
 <!ENTITY social.sharePopup.shared.label   "You shared this page.">
 <!ENTITY social.sharePopup.portrait.arialabel "User profile picture">
+
 <!ENTITY social.toggleSidebar.label "Show sidebar">
 <!ENTITY social.toggleSidebar.accesskey "s">
+
+<!ENTITY social.activated.button.label "Oops, undo">
+<!ENTITY social.activated.button.accesskey "u">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -367,8 +367,19 @@ telemetryOptOutPrompt = %1$S sends infor
 # LOCALIZATION NOTE (fullscreen.entered): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.entered=%S is now fullscreen.
 # LOCALIZATION NOTE (fullscreen.rememberDecision): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.rememberDecision=Remember decision for %S
 
 social.shareButton.tooltip=Share this
 social.shareButton.sharedtooltip=You shared this
 social.pageShared.label=Page shared
+
+# LOCALIZATION NOTE (social.enable.label): %S = Social networking provider
+social.enable.label=%S integration
+social.enable.accesskey=n
+
+# LOCALIZATION NOTE (social.remove.label): %S = brandShortName
+social.remove.label=Remove from %S
+social.remove.accesskey=R
+
+# LOCALIZATION NOTE (social.enabled.message): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
+social.activated.message=%1$S integration with %2$S has been activated.
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -12,16 +12,17 @@ const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
   "resource://gre/modules/SocialService.jsm");
 
 let Social = {
+  lastEventReceived: 0,
   provider: null,
   init: function Social_init(callback) {
     if (this.provider) {
       schedule(callback);
       return;
     }
 
     // Eventually this might want to retrieve a specific provider, but for now
@@ -33,16 +34,35 @@ let Social = {
       Services.obs.notifyObservers(null, "test-social-ui-ready", "");
     }.bind(this));
   },
 
   get uiVisible() {
     return this.provider && this.provider.enabled && this.provider.port;
   },
 
+  set enabled(val) {
+    SocialService.enabled = val;
+  },
+  get enabled() {
+    return SocialService.enabled;
+  },
+
+  get active() {
+    return Services.prefs.getBoolPref("social.active");
+  },
+  set active(val) {
+    Services.prefs.setBoolPref("social.active", !!val);
+    this.enabled = !!val;
+  },
+
+  toggle: function Social_toggle() {
+    this.enabled = !this.enabled;
+  },
+
   toggleSidebar: function SocialSidebar_toggle() {
     let prefValue = Services.prefs.getBoolPref("social.sidebar.open");
     Services.prefs.setBoolPref("social.sidebar.open", !prefValue);
   },
 
   sendWorkerMessage: function Social_sendWorkerMessage(message) {
     // Responses aren't handled yet because there is no actions to perform
     // based on the response from the provider at this point.
--- a/build/virtualenv/packages.txt
+++ b/build/virtualenv/packages.txt
@@ -1,9 +1,9 @@
 setup.py:other-licenses/simplejson-2.1.1:develop
 setup.py:testing/mozbase/manifestdestiny:develop
 setup.py:testing/mozbase/mozinfo:develop
 setup.py:testing/mozbase/mozinstall:develop
 setup.py:testing/mozbase/mozlog:develop
 setup.py:testing/mozbase/mozprocess:develop
 setup.py:testing/mozbase/mozprofile:develop
 setup.py:testing/mozbase/mozrunner:develop
-setup.py:build/pylib/blessings:develop
+setup.py:python/blessings:develop
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -286,21 +286,19 @@ HOST_CMMOBJS = $(addprefix host_,$(HOST_
 ifndef HOST_OBJS
 _HOST_OBJS = $(HOST_COBJS) $(HOST_CCOBJS) $(HOST_CPPOBJS) $(HOST_CMOBJS) $(HOST_CMMOBJS)
 HOST_OBJS = $(strip $(_HOST_OBJS))
 endif
 
 ifndef MOZ_AUTO_DEPS
 ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
 MDDEPFILES		= $(addprefix $(MDDEPDIR)/,$(OBJS:=.pp))
-ifndef NO_GEN_XPT
 MDDEPFILES		+= $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.h.pp) $(XPIDLSRCS:.idl=.xpt.pp))
 endif
 endif
-endif
 
 ALL_TRASH = \
 	$(GARBAGE) $(TARGETS) $(OBJS) $(PROGOBJS) LOGS TAGS a.out \
 	$(filter-out $(ASFILES),$(OBJS:.$(OBJ_SUFFIX)=.s)) $(OBJS:.$(OBJ_SUFFIX)=.ii) \
 	$(OBJS:.$(OBJ_SUFFIX)=.i) $(OBJS:.$(OBJ_SUFFIX)=.i_o) \
 	$(HOST_PROGOBJS) $(HOST_OBJS) $(IMPORT_LIBRARY) $(DEF_FILE)\
 	$(EXE_DEF_FILE) so_locations _gen _stubs $(wildcard *.res) $(wildcard *.RES) \
 	$(wildcard *.pdb) $(CODFILE) $(MAPFILE) $(IMPORT_LIBRARY) \
@@ -1293,17 +1291,16 @@ xpidl-preqs = \
 $(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) \
 	  $(PLY_INCLUDE) \
 	  $(LIBXUL_DIST)/sdk/bin/header.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
 	@if test -n "$(findstring $*.h, $(EXPORTS))"; \
 	  then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi
 
-ifndef NO_GEN_XPT
 # generate intermediate .xpt files into $(XPIDL_GEN_DIR), then link
 # into $(XPIDL_MODULE).xpt and export it to $(FINAL_TARGET)/components.
 $(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) \
 	  $(PLY_INCLUDE) \
 	  -I$(topsrcdir)/xpcom/typelib/xpt/tools \
 	  $(LIBXUL_DIST)/sdk/bin/typelib.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
@@ -1318,18 +1315,16 @@ libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).
 ifndef NO_DIST_INSTALL
 	$(call install_cmd,$(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components)
 ifndef NO_INTERFACES_MANIFEST
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
 endif
 endif
 
-endif # NO_GEN_XPT
-
 GARBAGE_DIRS		+= $(XPIDL_GEN_DIR)
 
 endif #} XPIDLSRCS
 
 
 ifndef INCLUDED_XPIDL_MK
   include $(topsrcdir)/config/makefiles/xpidl.mk
 endif
--- a/configure.in
+++ b/configure.in
@@ -358,16 +358,20 @@ else
     if test -z "$HOST_AR"; then
         HOST_AR="$AR"
     fi
     if test -z "$HOST_AR_FLAGS"; then
         HOST_AR_FLAGS="$AR_FLAGS"
     fi
 fi
 
+if test -n "$MOZ_WINCONSOLE"; then
+    AC_DEFINE(MOZ_WINCONSOLE)
+fi
+
 MOZ_TOOL_VARIABLES
 
 dnl ========================================================
 dnl Special win32 checks
 dnl ========================================================
 
 # With win8, sdk target=602, WINVER=602
 MOZ_ARG_ENABLE_BOOL(metro,
@@ -4201,16 +4205,17 @@ NECKO_COOKIES=1
 NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciwyg device"
 USE_ARM_KUSER=
 BUILD_CTYPES=1
 MOZ_USE_NATIVE_POPUP_WINDOWS=
 MOZ_ANDROID_HISTORY=
 MOZ_WEBSMS_BACKEND=
 MOZ_GRAPHITE=1
 ACCESSIBILITY=1
+MOZ_SYS_MSG=
 
 case "$target_os" in
     mingw*)
         NS_ENABLE_TSF=1
         AC_DEFINE(NS_ENABLE_TSF)
         ;;
 esac
 
@@ -7308,36 +7313,38 @@ fi
 dnl ========================================================
 dnl = Enable Radio Interface for B2G (Gonk usually)
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(b2g-ril,
 [  --enable-b2g-ril      Set compile flags necessary for testing B2G Radio Interface Layer via network sockets ],
     MOZ_B2G_RIL=1,
     MOZ_B2G_RIL= )
 if test -n "$MOZ_B2G_RIL"; then
-   AC_DEFINE(MOZ_B2G_RIL)
+    AC_DEFINE(MOZ_B2G_RIL)
 fi
 AC_SUBST(MOZ_B2G_RIL)
 
 dnl ========================================================
 dnl = Enable Bluetooth Interface for B2G (Gonk usually)
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(b2g-bt,
 [  --enable-b2g-bt      Set compile flags necessary for compiling Bluetooth API for B2G ],
     MOZ_B2G_BT=1,
     MOZ_B2G_BT= )
 if test -n "$MOZ_B2G_BT"; then
-   AC_DEFINE(MOZ_B2G_BT)
+    AC_DEFINE(MOZ_B2G_BT)
 fi
 AC_SUBST(MOZ_B2G_BT)
 
 dnl ========================================================
 dnl = Enable Support for System Messages API
 dnl ========================================================
-
+if test -n "$MOZ_SYS_MSG"; then
+    AC_DEFINE(MOZ_SYS_MSG)
+fi
 AC_SUBST(MOZ_SYS_MSG)
 
 dnl ========================================================
 dnl = Support for demangling undefined symbols
 dnl ========================================================
 if test -z "$SKIP_LIBRARY_CHECKS"; then
     AC_LANG_SAVE
     AC_LANG_CPLUSPLUS
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -173,18 +173,16 @@ MOCHITEST_FILES_A = \
 		test_bug424212.html \
 		test_bug425013.html \
 		bug426308-redirect.sjs \
 		test_bug426308.html \
 		test_bug426646.html \
 		file_bug426646-1.html \
 		file_bug426646-2.html \
 		test_bug429157.html \
-		test_header.html \
-		header.sjs \
 		test_XHR.html \
 		file_XHR_pass1.xml \
 		file_XHR_pass2.txt \
 		file_XHR_pass3.txt \
 		file_XHR_pass3.txt^headers^ \
 		file_XHR_fail1.txt \
 		file_XHR_fail1.txt^headers^ \
 		file_XHR_binary1.bin \
deleted file mode 100644
--- a/content/base/test/header.sjs
+++ /dev/null
@@ -1,8 +0,0 @@
-function handleRequest(request, response) {
-  response.setHeader("Content-Type", "text/plain", false);
-  response.setHeader("Cache-Control", "no-cache", false);
-
-  var value = request.hasHeader("SomeHeader") ? request.getHeader("SomeHeader")
-                                             : "";
-  response.write("SomeHeader: " + value);
-}
deleted file mode 100644
--- a/content/base/test/test_header.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for XHR header preservation</title>
-  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-    /** Test for Bug 421622 **/
-    const SJS_URL = "http://mochi.test:8888/tests/content/base/test/header.sjs";
-    const VALUE = "http://www.mozilla.org/";
-
-    var req = new XMLHttpRequest();
-    req.open("GET", SJS_URL, false);
-    req.setRequestHeader("SomeHeader", VALUE);
-    req.send(null);
-
-    is(req.responseText,
-       "SomeHeader: " + VALUE,
-       "Header received by server does not match what was set");
-</script>
-</pre>
-</body>
-</html>
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -31,18 +31,16 @@ CPPSRCS		= \
 		nsDOMUIEvent.cpp \
 		nsDOMKeyboardEvent.cpp \
 		nsDOMTextEvent.cpp \
 		nsDOMMouseEvent.cpp \
 		nsDOMMouseScrollEvent.cpp \
 		nsDOMDragEvent.cpp \
 		nsDOMMutationEvent.cpp \
 		nsDOMPopupBlockedEvent.cpp \
-		nsDOMDeviceLightEvent.cpp \
-		nsDOMDeviceOrientationEvent.cpp \
 		nsDOMDeviceMotionEvent.cpp \
 		nsDOMBeforeUnloadEvent.cpp \
 		nsDOMXULCommandEvent.cpp \
 		nsDOMCommandEvent.cpp \
 		nsDOMMessageEvent.cpp \
 		nsPaintRequest.cpp \
 		nsPrivateTextRange.cpp \
 		nsXMLEventsManager.cpp \
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceLightEvent.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsDOMClassInfoID.h"
-#include "nsDOMDeviceLightEvent.h"
-#include "DictionaryHelpers.h"
-
-NS_IMPL_ADDREF_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
-
-DOMCI_DATA(DeviceLightEvent, nsDOMDeviceLightEvent)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMDeviceLightEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceLightEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceLightEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
-
-NS_IMETHODIMP
-nsDOMDeviceLightEvent::InitDeviceLightEvent(const nsAString & aEventTypeArg,
-                                            bool aCanBubbleArg,
-                                            bool aCancelableArg,
-                                            double aValue)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mValue = aValue;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMDeviceLightEvent::GetValue(double *aValue)
-{
-  NS_ENSURE_ARG_POINTER(aValue);
-  *aValue = mValue;
-  return NS_OK;
-}
-
-nsresult
-nsDOMDeviceLightEvent::InitFromCtor(const nsAString& aType,
-                                    JSContext* aCx, jsval* aVal)
-{
-  mozilla::dom::DeviceLightEventInit d;
-  nsresult rv = d.Init(aCx, aVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return InitDeviceLightEvent(aType, d.bubbles, d.cancelable, d.value);
-}
-
-nsresult
-NS_NewDOMDeviceLightEvent(nsIDOMEvent** aInstancePtrResult,
-                          nsPresContext* aPresContext,
-                          nsEvent *aEvent) 
-{
-  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
-  nsDOMDeviceLightEvent* it = new nsDOMDeviceLightEvent(aPresContext, aEvent);
-  return CallQueryInterface(it, aInstancePtrResult);
-}
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceLightEvent.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsDOMDeviceLightEvent_h__
-#define nsDOMDeviceLightEvent_h__
-
-#include "nsIDOMDeviceLightEvent.h"
-#include "nsDOMEvent.h"
-
-class nsDOMDeviceLightEvent
- : public nsDOMEvent
- , public nsIDOMDeviceLightEvent
-{
-public:
-
-  nsDOMDeviceLightEvent(nsPresContext* aPresContext, nsEvent* aEvent)
-  : nsDOMEvent(aPresContext, aEvent),
-    mValue(0) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // Forward to nsDOMEvent
-  NS_FORWARD_TO_NSDOMEVENT
-
-  // nsIDOMDeviceLightEvent Interface
-  NS_DECL_NSIDOMDEVICELIGHTEVENT
-
-  virtual nsresult InitFromCtor(const nsAString& aType,
-                                JSContext* aCx,
-                                jsval* aVal);
-protected:
-  double mValue;
-};
-
-#endif
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceOrientationEvent.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsDOMClassInfoID.h"
-#include "nsDOMDeviceOrientationEvent.h"
-
-NS_IMPL_ADDREF_INHERITED(nsDOMDeviceOrientationEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMDeviceOrientationEvent, nsDOMEvent)
-
-DOMCI_DATA(DeviceOrientationEvent, nsDOMDeviceOrientationEvent)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMDeviceOrientationEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceOrientationEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::InitDeviceOrientationEvent(const nsAString & aEventTypeArg,
-                                                                      bool aCanBubbleArg,
-                                                                      bool aCancelableArg,
-                                                                      double aAlpha,
-                                                                      double aBeta,
-                                                                      double aGamma,
-                                                                      bool aAbsolute)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mAlpha = aAlpha;
-  mBeta = aBeta;
-  mGamma = aGamma;
-  mAbsolute = aAbsolute;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetAlpha(double *aAlpha)
-{
-  NS_ENSURE_ARG_POINTER(aAlpha);
-
-  *aAlpha = mAlpha;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetBeta(double *aBeta)
-{
-  NS_ENSURE_ARG_POINTER(aBeta);
-
-  *aBeta = mBeta;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetGamma(double *aGamma)
-{
-  NS_ENSURE_ARG_POINTER(aGamma);
-
-  *aGamma = mGamma;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetAbsolute(bool *aAbsolute)
-{
-  NS_ENSURE_ARG_POINTER(aAbsolute);
-
-  *aAbsolute = mAbsolute;
-  return NS_OK;
-}
-
-nsresult NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aInstancePtrResult,
-                                         nsPresContext* aPresContext,
-                                         nsEvent *aEvent) 
-{
-  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
-
-  nsDOMDeviceOrientationEvent* it = new nsDOMDeviceOrientationEvent(aPresContext, aEvent);
-  if (nsnull == it) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  return CallQueryInterface(it, aInstancePtrResult);
-}
deleted file mode 100644
--- a/content/events/src/nsDOMDeviceOrientationEvent.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsDOMDeviceOrientationEvent_h__
-#define nsDOMDeviceOrientationEvent_h__
-
-#include "nsIDOMDeviceOrientationEvent.h"
-#include "nsDOMEvent.h"
-
-class nsDOMDeviceOrientationEvent : public nsDOMEvent,
-                                    public nsIDOMDeviceOrientationEvent
-{
-public:
-
-  nsDOMDeviceOrientationEvent(nsPresContext* aPresContext, nsEvent* aEvent)
-  : nsDOMEvent(aPresContext, aEvent),
-    mAlpha(0),
-    mBeta(0),
-    mGamma(0),
-    mAbsolute(true) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // Forward to nsDOMEvent
-  NS_FORWARD_TO_NSDOMEVENT
-
-  // nsIDOMDeviceOrientationEvent Interface
-  NS_DECL_NSIDOMDEVICEORIENTATIONEVENT
-
-protected:
-  double mAlpha, mBeta, mGamma;
-  bool mAbsolute;
-};
-
-#endif
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -420,16 +420,34 @@ is(receivedEvent, e, "Wrong event!");
 // DeviceLightEvent
 e = new DeviceLightEvent("hello", {value: 1} );
 ok(e.type, "hello", "Wrong event type!");
 ok(!e.isTrusted, "Event should not be trusted");
 is(e.value, 1, "value should be 1");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
+// DeviceOrientationEvent
+e = new DeviceOrientationEvent("hello");
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event should not be trusted");
+is(e.alpha, 0);
+is(e.beta, 0);
+is(e.gamma, 0);
+is(e.absolute, false);
+
+e = new DeviceOrientationEvent("hello", { alpha: 1, beta: 2, gamma: 3, absolute: true } );
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event should not be trusted");
+is(e.alpha, 1);
+is(e.beta, 2);
+is(e.gamma, 3);
+is(e.absolute, true);
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
 
 // MouseEvent
 
 try {
   e = new MouseEvent();
 } catch(exp) {
   ex = true;
 }
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4897,16 +4897,23 @@ nsDocShell::GetParentNativeWindow(native
 
 NS_IMETHODIMP
 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsDocShell::GetNativeHandle(nsAString& aNativeHandle)
+{
+    // the nativeHandle should be accessed from nsIXULWindow
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsDocShell::GetVisibility(bool * aVisibility)
 {
     NS_ENSURE_ARG_POINTER(aVisibility);
 
     *aVisibility = false;
 
     if (!mContentViewer)
         return NS_OK;
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -223,34 +223,34 @@ let AlarmService = {
       ppmm.sendAsyncMessage("AlarmsManager:" + aMessageName, json);
   },
 
   _onAlarmFired: function _onAlarmFired() {
     debug("_onAlarmFired()");
 
     if (this._currentAlarm) {
       debug("Fire system intent: " + JSON.stringify(this._currentAlarm));
-      if (this._currentAlarm.manifestURL)
-        messenger.sendMessage("alarm", this._currentAlarm, this._currentAlarm.manifestURL);
+      let manifestURI = Services.io.newURI(this._currentAlarm.manifestURL, null, null);
+      messenger.sendMessage("alarm", this._currentAlarm, manifestURI);
       this._currentAlarm = null;
     }
 
     // reset the next alarm from the queue
     let nowTime = Date.now();
     let alarmQueue = this._alarmQueue;
     while (alarmQueue.length > 0) {
       let nextAlarm = alarmQueue.shift();
       let nextAlarmTime = this._getAlarmTime(nextAlarm);
 
       // if the next alarm has been expired, directly 
       // fire system intent for it instead of setting it
       if (nextAlarmTime <= nowTime) {
         debug("Fire system intent: " + JSON.stringify(nextAlarm));
-        if (nextAlarm.manifestURL)
-          messenger.sendMessage("alarm", nextAlarm, nextAlarm.manifestURL);
+        let manifestURI = Services.io.newURI(nextAlarm.manifestURL, null, null);
+        messenger.sendMessage("alarm", nextAlarm, manifestURI);
       } else {
         this._currentAlarm = nextAlarm;
         break;
       }
     }
     this._debugCurrentAlarm();
   },
 
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -40,16 +40,21 @@ AlarmsManager.prototype = {
                                       contractID: ALARMSMANAGER_CONTRACTID,
                                       classDescription: "AlarmsManager",
                                       interfaces: [nsIDOMMozAlarmsManager],
                                       flags: nsIClassInfo.DOM_OBJECT }),
 
   add: function add(aDate, aRespectTimezone, aData) {
     debug("add()");
 
+    if (!this._manifestURL) {
+      debug("Cannot add alarms for non-installed apps.");
+      throw Components.results.NS_ERROR_FAILURE;
+    }
+
     let isIgnoreTimezone = true;
     switch (aRespectTimezone) {
       case "honorTimezone":
         isIgnoreTimezone = false;
         break;
 
       case "ignoreTimezone":
         isIgnoreTimezone = true;
@@ -145,18 +150,17 @@ AlarmsManager.prototype = {
     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
 
     // Add the valid messages to be listened.
     this.initHelper(aWindow, ["AlarmsManager:Add:Return:OK", "AlarmsManager:Add:Return:KO", 
                               "AlarmsManager:GetAll:Return:OK", "AlarmsManager:GetAll:Return:KO"]);
 
     // Get the manifest URL if this is an installed app
     this._manifestURL = null;
-    let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     let app = utils.getApp();
     if (app)
       this._manifestURL = app.manifestURL;
   },
 
   // Called from DOMRequestIpcHelper.
   uninit: function uninit() {
     debug("uninit()");
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1293,17 +1293,17 @@ Navigator::GetMozBluetooth(nsIDOMBluetoo
   return NS_OK;
 }
 #endif //MOZ_B2G_BT
 
 //*****************************************************************************
 //    nsNavigator::nsIDOMNavigatorSystemMessages
 //*****************************************************************************
 #ifdef MOZ_SYS_MSG
-NS_IMETHODIMP
+nsresult
 Navigator::EnsureMessagesManager()
 {
   if (mMessagesManager) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -293,18 +293,16 @@
 #include "nsIDOMMozCSSKeyframesRule.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsDOMCSSValueList.h"
 #define MOZ_GENERATED_EVENTS_INCLUDES
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENTS_INCLUDES
-#include "nsIDOMDeviceLightEvent.h"
-#include "nsIDOMDeviceOrientationEvent.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMNodeIterator.h"
 #include "nsIDOMTreeWalker.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIDOMCrypto.h"
@@ -810,30 +808,24 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(DragEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(KeyboardEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CompositionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PopupBlockedEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  // Device Light
-  NS_DEFINE_CLASSINFO_DATA(DeviceLightEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface)                \
   NS_DEFINE_CLASSINFO_DATA(_event_interface, nsDOMGenericSH, \
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
 
-  // Device Orientation
-  NS_DEFINE_CLASSINFO_DATA(DeviceOrientationEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceMotionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceRotationRate, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // Misc HTML classes
@@ -1725,17 +1717,16 @@ static const nsContractIDMapData kConstr
     return rv;                                              \
   }
 
 NS_DEFINE_EVENT_CTOR(Event)
 NS_DEFINE_EVENT_CTOR(MozSettingsEvent)
 NS_DEFINE_EVENT_CTOR(MozApplicationEvent)
 NS_DEFINE_EVENT_CTOR(UIEvent)
 NS_DEFINE_EVENT_CTOR(MouseEvent)
-NS_DEFINE_EVENT_CTOR(DeviceLightEvent)
 #ifdef MOZ_B2G_RIL
 NS_DEFINE_EVENT_CTOR(MozWifiStatusChangeEvent)
 NS_DEFINE_EVENT_CTOR(MozWifiConnectionInfoEvent)
 #endif
 
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CTOR(_event_interface)
@@ -1773,17 +1764,16 @@ static const nsConstructorFuncMapData kC
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, nsDOMMultipartFile::NewBlob)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozSettingsEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozApplicationEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
-  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(DeviceLightEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
 #ifdef MOZ_B2G_RIL
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiStatusChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiConnectionInfoEvent)
 #endif
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(_event_interface)
@@ -2595,35 +2585,25 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(PopupBlockedEvent, nsIDOMPopupBlockedEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPopupBlockedEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(DeviceLightEvent, nsIDOMDeviceLightEvent)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceLightEvent)
-    DOM_CLASSINFO_EVENT_MAP_ENTRIES
-  DOM_CLASSINFO_MAP_END
-
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface)                         \
   DOM_CLASSINFO_MAP_BEGIN(_event_interface, nsIDOM##_event_interface) \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOM##_event_interface)                 \
     DOM_CLASSINFO_EVENT_MAP_ENTRIES                                   \
   DOM_CLASSINFO_MAP_END
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
 
-  DOM_CLASSINFO_MAP_BEGIN(DeviceOrientationEvent, nsIDOMDeviceOrientationEvent)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
-    DOM_CLASSINFO_EVENT_MAP_ENTRIES
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(DeviceMotionEvent, nsIDOMDeviceMotionEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceMotionEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DeviceAcceleration, nsIDOMDeviceAcceleration)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceAcceleration)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
@@ -5968,16 +5948,19 @@ DefineIDBInterfaceConstants(JSContext *c
     interface = IDBConstant::IDBCursor;
   }
   else if (aIID->Equals(NS_GET_IID(nsIIDBRequest))) {
     interface = IDBConstant::IDBRequest;
   }
   else if (aIID->Equals(NS_GET_IID(nsIIDBTransaction))) {
     interface = IDBConstant::IDBTransaction;
   }
+  else {
+    MOZ_NOT_REACHED("unexpected IID");
+  }
 
   for (int8_t i = 0; i < (int8_t)mozilla::ArrayLength(sIDBConstants); ++i) {
     const IDBConstant& c = sIDBConstants[i];
     if (c.interface != interface) {
       continue;
     }
 
     if (!JS_DefineProperty(cx, obj, c.name, JSVAL_VOID,
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -38,22 +38,20 @@ DOMCI_CLASS(Event)
 DOMCI_CLASS(MutationEvent)
 DOMCI_CLASS(UIEvent)
 DOMCI_CLASS(MouseEvent)
 DOMCI_CLASS(MouseScrollEvent)
 DOMCI_CLASS(DragEvent)
 DOMCI_CLASS(KeyboardEvent)
 DOMCI_CLASS(CompositionEvent)
 DOMCI_CLASS(PopupBlockedEvent)
-DOMCI_CLASS(DeviceLightEvent)
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) DOMCI_CLASS(_event_interface)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
-DOMCI_CLASS(DeviceOrientationEvent)
 DOMCI_CLASS(DeviceMotionEvent)
 DOMCI_CLASS(DeviceAcceleration)
 DOMCI_CLASS(DeviceRotationRate)
 
 // HTML classes
 DOMCI_CLASS(HTMLDocument)
 DOMCI_CLASS(HTMLOptionsCollection)
 DOMCI_CLASS(HTMLCollection)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9395,19 +9395,17 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
 
     timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     nsRefPtr<nsTimeout> copy = timeout;
 
-    rv = timeout->mTimer->InitWithFuncCallback(TimerCallback, timeout,
-                                               realInterval,
-                                               nsITimer::TYPE_ONE_SHOT);
+    rv = timeout->InitTimer(TimerCallback, realInterval);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // The timeout is now also held in the timer's closure.
     copy.forget();
   } else {
     // If we are frozen, however, then we instead simply set
@@ -9632,20 +9630,17 @@ nsGlobalWindow::RescheduleTimeout(nsTime
   // Reschedule the OS timer. Don't bother returning any error codes if
   // this fails since the callers of this method don't care about them.
 
   // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
   // PRTime to make the division do the right thing on 64-bit
   // platforms whether delay is positive or negative (which we
   // know is always positive here, but cast anyways for
   // consistency).
-  nsresult rv = aTimeout->mTimer->
-    InitWithFuncCallback(TimerCallback, aTimeout,
-                         delay.ToMilliseconds(),
-                         nsITimer::TYPE_ONE_SHOT);
+  nsresult rv = aTimeout->InitTimer(TimerCallback, delay.ToMilliseconds());
 
   if (NS_FAILED(rv)) {
     NS_ERROR("Error initializing timer for DOM timeout!");
 
     // We failed to initialize the new OS timer, this timer does
     // us no good here so we just cancel it (just in case) and
     // null out the pointer to the OS timer, this will release the
     // OS timer. As we continue executing the code below we'll end
@@ -9977,21 +9972,17 @@ nsresult nsGlobalWindow::ResetTimersForN
       PR_REMOVE_LINK(timeout);
       // InsertTimeoutIntoList will addref |timeout| and reset
       // mFiringDepth.  Make sure to undo that after calling it.
       PRUint32 firingDepth = timeout->mFiringDepth;
       InsertTimeoutIntoList(timeout);
       timeout->mFiringDepth = firingDepth;
       timeout->Release();
 
-      nsresult rv =
-        timeout->mTimer->InitWithFuncCallback(TimerCallback,
-                                              timeout,
-                                              delay.ToMilliseconds(),
-                                              nsITimer::TYPE_ONE_SHOT);
+      nsresult rv = timeout->InitTimer(TimerCallback, delay.ToMilliseconds());
 
       if (NS_FAILED(rv)) {
         NS_WARNING("Error resetting non background timer for DOM timeout!");
         return rv;
       }
 
       timeout = nextTimeout;
     } else {
@@ -10494,18 +10485,17 @@ nsGlobalWindow::ResumeTimeouts(bool aTha
 
       // Set mWhen back to the time when the timer is supposed to
       // fire.
       t->mWhen = now + t->mTimeRemaining;
 
       t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
       NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
 
-      rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
-                                           nsITimer::TYPE_ONE_SHOT);
+      rv = t->InitTimer(TimerCallback, delay);
       if (NS_FAILED(rv)) {
         t->mTimer = nsnull;
         return rv;
       }
 
       // Add a reference for the new timer's closure.
       t->AddRef();
     }
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -148,16 +148,21 @@ struct nsTimeout : PRCList
     return static_cast<nsTimeout*>(PR_NEXT_LINK(this));
   }
 
   nsTimeout* Prev() {
     // Note: might not actually return an nsTimeout.  Use IsTimeout to check.
     return static_cast<nsTimeout*>(PR_PREV_LINK(this));
   }
 
+  nsresult InitTimer(nsTimerCallbackFunc aFunc, PRUint64 delay) {
+    return mTimer->InitWithFuncCallback(aFunc, this, delay,
+                                        nsITimer::TYPE_ONE_SHOT);
+  }
+
   // Window for which this timeout fires
   nsRefPtr<nsGlobalWindow> mWindow;
 
   // The actual timer object
   nsCOMPtr<nsITimer> mTimer;
 
   // True if the timeout was cleared
   bool mCleared;
--- a/dom/bindings/PrimitiveConversions.h
+++ b/dom/bindings/PrimitiveConversions.h
@@ -75,18 +75,19 @@ struct PrimitiveConversionTraits<int32_t
 template<>
 struct PrimitiveConversionTraits<uint32_t> : PrimitiveConversionTraits_smallInt {
 };
 
 template<>
 struct PrimitiveConversionTraits<bool> {
   typedef JSBool jstype;
   typedef bool intermediateType;
-  static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) {
-    return JS_ValueToBoolean(cx, v, retval);
+  static inline bool converter(JSContext* /* unused */, JS::Value v, jstype* retval) {
+    *retval = JS::ToBoolean(v);
+    return true;
   }
 };
 
 template<>
 struct PrimitiveConversionTraits<int64_t> {
   typedef int64_t jstype;
   typedef int64_t intermediateType;
   static inline bool converter(JSContext* cx, JS::Value v, jstype* retval) {
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -398,18 +398,20 @@ EventFilter(DBusConnection* aConn, DBusM
 
   signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
   BluetoothValue v;
   
   if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceFound")) {
 
     DBusMessageIter iter;
 
-    NS_ASSERTION(dbus_message_iter_init(aMsg, &iter),
-                 "Can't create message iterator!");
+    if (!dbus_message_iter_init(aMsg, &iter)) {
+      NS_WARNING("Can't create iterator!");
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
 
     InfallibleTArray<BluetoothNamedValue> value;
     const char* addr;
     dbus_message_iter_get_basic(&iter, &addr);
     value.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
                                             NS_ConvertUTF8toUTF16(addr)));
     
     if (dbus_message_iter_next(&iter)) {
--- a/dom/devicestorage/test/test_basic.html
+++ b/dom/devicestorage/test/test_basic.html
@@ -8,30 +8,40 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <title>Test for the device storage API </title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="devicestorage_common.js"></script>
 
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
-<body>
+<body onunload="unload()">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717103">Mozilla Bug 717103</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
+function unload() {
+  delete gDataBlob;
+  gDataBlob = null;
+
+  delete gFileReader;
+  gFileReader = null;
+}
+
+
 devicestorage_setup();
 
 var gFileName = "devicestorage/hi";
 var gData = "My name is Doug Turner.  My IRC nick is DougT.  I like Maple cookies."
 var gDataBlob = new Blob([gData], {type: 'text/plain'});
+var gFileReader = new FileReader();
 
 function getAfterDeleteSuccess(e) {
   ok(false, "file was deleted not successfully");
   devicestorage_cleanup();
 }
 
 function getAfterDeleteError(e) {
   ok(true, "file was deleted successfully");
@@ -58,19 +68,18 @@ function deleteError(e) {
 function getSuccess(e) {
   var storage = navigator.getDeviceStorage("testing");
   ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
 
   ok(e.target.result.name == gFileName, "File name should match");
 
   var name = e.target.result.name;
 
-  var reader = new FileReader();
-  reader.readAsArrayBuffer(gDataBlob);
-  reader.onload = function(e) {
+  gFileReader.readAsArrayBuffer(gDataBlob);
+  gFileReader.onload = function(e) {
     readerCallback(e);
 
     request = storage[0].delete(name)
     request.onsuccess = deleteSuccess;
     request.onerror = deleteError;
   }
 }
 
--- a/dom/interfaces/events/nsIDOMDeviceOrientationEvent.idl
+++ b/dom/interfaces/events/nsIDOMDeviceOrientationEvent.idl
@@ -36,8 +36,15 @@ interface nsIDOMDeviceOrientationEvent :
    */
 
   readonly attribute double alpha;
   readonly attribute double beta;
   readonly attribute double gamma;
   readonly attribute boolean absolute;
 };
 
+dictionary DeviceOrientationEventInit : EventInit
+{
+  double alpha;
+  double beta;
+  double gamma;
+  boolean absolute;
+};
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -199,20 +199,16 @@ nsresult
 NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsKeyEvent *aEvent);
 nsresult
 NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsCompositionEvent *aEvent);
 nsresult
 NS_NewDOMMutationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsMutationEvent* aEvent);
 nsresult
 NS_NewDOMPopupBlockedEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
-NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
-nsresult
-NS_NewDOMDeviceLightEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
-nsresult
 NS_NewDOMDeviceMotionEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMTextEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsTextEvent* aEvent);
 nsresult
 NS_NewDOMBeforeUnloadEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMSVGEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsEvent* aEvent);
 nsresult
--- a/dom/ipc/CrashReporterParent.cpp
+++ b/dom/ipc/CrashReporterParent.cpp
@@ -12,25 +12,25 @@
 using namespace base;
 
 namespace mozilla {
 namespace dom {
 
 void
 CrashReporterParent::ActorDestroy(ActorDestroyReason why)
 {
-#if defined(__ANDROID__) && defined(MOZ_CRASHREPORTER)
+#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER)
   CrashReporter::RemoveLibraryMappingsForChild(ProcessId(OtherProcess()));
 #endif
 }
 
 bool
 CrashReporterParent::RecvAddLibraryMappings(const InfallibleTArray<Mapping>& mappings)
 {
-#if defined(__ANDROID__) && defined(MOZ_CRASHREPORTER)
+#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER)
   for (PRUint32 i = 0; i < mappings.Length(); i++) {
     const Mapping& m = mappings[i];
     CrashReporter::AddLibraryMappingForChild(ProcessId(OtherProcess()),
                                              m.library_name().get(),
                                              m.file_id().get(),
                                              m.start_address(),
                                              m.mapping_length(),
                                              m.file_offset());
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -1942,16 +1942,78 @@ nsPluginHost::IsLiveTag(nsIPluginTag* aP
   for (tag = mPlugins; tag; tag = tag->mNext) {
     if (tag == aPluginTag) {
       return true;
     }
   }
   return false;
 }
 
+nsPluginTag*
+nsPluginHost::HaveSamePlugin(const nsPluginTag* aPluginTag)
+{
+  for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
+    if (tag->HasSameNameAndMimes(aPluginTag)) {
+        return tag;
+    }
+  }
+  return nsnull;
+}
+
+nsPluginTag*
+nsPluginHost::FirstPluginWithPath(const nsCString& path)
+{
+  for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
+    if (tag->mFullPath.Equals(path)) {
+      return tag;
+    }
+  }
+  return nsnull;
+}
+
+namespace {
+
+PRInt64 GetPluginLastModifiedTime(const nsCOMPtr<nsIFile>& localfile)
+{
+  PRInt64 fileModTime = LL_ZERO;
+
+#if defined(XP_MACOSX)
+  // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
+  // is a much better guide to when it was last modified than the date of
+  // its package directory.  See bug 313700.
+  nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(localfile);
+  if (localFileMac) {
+    localFileMac->GetBundleContentsLastModifiedTime(&fileModTime);
+  } else {
+    localfile->GetLastModifiedTime(&fileModTime);
+  }
+#else
+  localfile->GetLastModifiedTime(&fileModTime);
+#endif
+
+  return fileModTime;
+}
+
+struct CompareFilesByTime 
+{
+  bool 
+  LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const 
+  {
+    return LL_CMP(GetPluginLastModifiedTime(a), <, GetPluginLastModifiedTime(b));
+  }
+
+  bool
+  Equals(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
+  {
+    return LL_EQ(GetPluginLastModifiedTime(a), GetPluginLastModifiedTime(b));
+  }
+};
+
+} // anonymous namespace
+
 typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
 
 nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
                                             bool aCreatePluginList,
                                             bool *aPluginsChanged)
 {
   NS_ENSURE_ARG_POINTER(aPluginsChanged);
   nsresult rv;
@@ -1986,41 +2048,30 @@ nsresult nsPluginHost::ScanPluginsDirect
     // See bug 197855.
     dirEntry->Normalize();
 
     if (nsPluginsDir::IsPluginFile(dirEntry)) {
       pluginFiles.AppendElement(dirEntry);
     }
   }
 
+  pluginFiles.Sort(CompareFilesByTime());
+
   bool warnOutdated = false;
 
-  for (PRUint32 i = 0; i < pluginFiles.Length(); i++) {
+  for (PRInt32 i = (pluginFiles.Length() - 1); i >= 0; i--) {
     nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
 
     nsString utf16FilePath;
     rv = localfile->GetPath(utf16FilePath);
     if (NS_FAILED(rv))
       continue;
 
-    PRInt64 fileModTime = LL_ZERO;
-#if defined(XP_MACOSX)
-    // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
-    // is a much better guide to when it was last modified than the date of
-    // its package directory.  See bug 313700.
-    nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(localfile);
-    if (localFileMac) {
-      localFileMac->GetBundleContentsLastModifiedTime(&fileModTime);
-    } else {
-      localfile->GetLastModifiedTime(&fileModTime);
-    }
-#else
-    localfile->GetLastModifiedTime(&fileModTime);
-#endif
-
+    PRInt64 fileModTime = GetPluginLastModifiedTime(localfile);
+    
     // Look for it in our cache
     NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
     nsRefPtr<nsPluginTag> pluginTag;
     RemoveCachedPluginsInfo(filePath.get(), getter_AddRefs(pluginTag));
 
     bool enabled = true;
     bool seenBefore = false;
     if (pluginTag) {
@@ -2141,16 +2192,31 @@ nsresult nsPluginHost::ScanPluginsDirect
       }
     }
 
     // do it if we still want it
     if (!seenBefore) {
       // We have a valid new plugin so report that plugins have changed.
       *aPluginsChanged = true;
     }
+    
+    // Avoid adding different versions of the same plugin if they are running 
+    // in-process, otherwise we risk undefined behaviour.
+    if (!nsNPAPIPlugin::RunPluginOOP(pluginTag)) {
+      if (nsPluginTag *duplicate = HaveSamePlugin(pluginTag)) {
+        continue;
+      }
+    }
+    
+    // Don't add the same plugin again if it hasn't changed
+    if (nsPluginTag* duplicate = FirstPluginWithPath(pluginTag->mFullPath)) {
+      if (LL_EQ(pluginTag->mLastModifiedTime, duplicate->mLastModifiedTime)) {
+        continue;
+      }
+    }
 
     // If we're not creating a plugin list, simply looking for changes,
     // then we're done.
     if (!aCreatePluginList) {
       return NS_OK;
     }
 
     pluginTag->SetHost(this);
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -262,16 +262,22 @@ private:
 
   // Given a file path, returns the plugins info from our cache
   // and removes it from the cache.
   void RemoveCachedPluginsInfo(const char *filePath,
                                nsPluginTag **result);
 
   // Checks to see if a tag object is in our list of live tags.
   bool IsLiveTag(nsIPluginTag* tag);
+  
+  // Checks our list of live tags for an equivalent tag.
+  nsPluginTag* HaveSamePlugin(const nsPluginTag * aPluginTag);
+    
+  // Returns the first plugin at |path|
+  nsPluginTag* FirstPluginWithPath(const nsCString& path);
 
   nsresult EnsurePrivateDirServiceProvider();
 
   void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag);
 
   nsRefPtr<nsPluginTag> mPlugins;
   nsRefPtr<nsPluginTag> mCachedPlugins;
   nsRefPtr<nsInvalidPluginTag> mInvalidPlugins;
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -374,16 +374,35 @@ PRUint32 nsPluginTag::Flags()
   return mFlags;
 }
 
 bool nsPluginTag::IsEnabled()
 {
   return HasFlag(NS_PLUGIN_FLAG_ENABLED) && !HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
 }
 
+bool
+nsPluginTag::HasSameNameAndMimes(const nsPluginTag *aPluginTag) const
+{
+  NS_ENSURE_TRUE(aPluginTag, false);
+
+  if ((!mName.Equals(aPluginTag->mName)) ||
+      (mMimeTypes.Length() != aPluginTag->mMimeTypes.Length())) {
+    return false;
+  }
+
+  for (PRUint32 i = 0; i < mMimeTypes.Length(); i++) {
+    if (!mMimeTypes[i].Equals(aPluginTag->mMimeTypes[i])) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void nsPluginTag::TryUnloadPlugin(bool inShutdown)
 {
   // We never want to send NPP_Shutdown to an in-process plugin unless
   // this process is shutting down.
   if (mLibrary && !inShutdown) {
     return;
   }
 
--- a/dom/plugins/base/nsPluginTags.h
+++ b/dom/plugins/base/nsPluginTags.h
@@ -53,16 +53,17 @@ public:
   virtual ~nsPluginTag();
   
   void SetHost(nsPluginHost * aHost);
   void TryUnloadPlugin(bool inShutdown);
   void Mark(PRUint32 mask);
   void UnMark(PRUint32 mask);
   bool HasFlag(PRUint32 flag);
   PRUint32 Flags();
+  bool HasSameNameAndMimes(const nsPluginTag *aPluginTag) const;
   bool IsEnabled();
   
   nsRefPtr<nsPluginTag> mNext;
   nsPluginHost *mPluginHost;
   nsCString     mName; // UTF-8
   nsCString     mDescription; // UTF-8
   nsTArray<nsCString> mMimeTypes; // UTF-8
   nsTArray<nsCString> mMimeDescriptions; // UTF-8
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -135,27 +135,27 @@ VoicemailStatus.prototype = {
 function RILContentHelper() {
   this.voiceConnectionInfo = new MobileConnectionInfo();
   this.dataConnectionInfo = new MobileConnectionInfo();
 
   this.initRequests();
   this.initMessageListener(RIL_IPC_MSG_NAMES);
   Services.obs.addObserver(this, "xpcom-shutdown", false);
 
-  // Request initial state.
-  let radioState = cpmm.QueryInterface(Ci.nsISyncMessageSender)
-                       .sendSyncMessage("RIL:GetRadioState")[0];
+  // Request initial context.
+  let rilContext = cpmm.QueryInterface(Ci.nsISyncMessageSender)
+                       .sendSyncMessage("RIL:GetRilContext")[0];
 
-  if (!radioState) {
-    debug("Received null radioState from chrome process.");
+  if (!rilContext) {
+    debug("Received null rilContext from chrome process.");
     return;
   }
-  this.cardState = radioState.cardState;
-  this.updateConnectionInfo(radioState.voice, this.voiceConnectionInfo);
-  this.updateConnectionInfo(radioState.data, this.dataConnectionInfo);
+  this.cardState = rilContext.cardState;
+  this.updateConnectionInfo(rilContext.voice, this.voiceConnectionInfo);
+  this.updateConnectionInfo(rilContext.data, this.dataConnectionInfo);
 }
 
 RILContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider,
                                          Ci.nsIRILContentHelper,
                                          Ci.nsIObserver]),
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -55,16 +55,17 @@ const DEFAULT_EMERGENCY_NUMBERS = ["112"
 
 let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = false;
 let RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = false;
 // This flag defaults to true since on RIL v6 and later, we get the
 // version number via the UNSOLICITED_RIL_CONNECTED parcel.
 let RILQUIRKS_V5_LEGACY = true;
 let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = false;
 let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = false;
+let RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = false;
 
 /**
  * This object contains helpers buffering incoming data & deconstructing it
  * into parcels as well as buffering outgoing data & constructing parcels.
  * For that it maintains two buffers and corresponding uint8 views, indexes.
  *
  * The incoming buffer is a circular buffer where we store incoming data.
  * As soon as a complete parcel is received, it is processed right away, so
@@ -722,16 +723,20 @@ let RIL = {
                   "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP");
           }
           RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true;
         }
         break;
       case "Qualcomm RIL 1.0":
         let product_model = libcutils.property_get("ro.product.model");
         if (DEBUG) debug("Detected product model " + product_model);
+        if (product_model == "otoro1") {
+          if (DEBUG) debug("Enabling RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS.");
+          RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = true;
+        }
         if (DEBUG) {
           debug("Detected Qualcomm RIL 1.0, " +
                 "disabling RILQUIRKS_V5_LEGACY and " +
                 "enabling RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE.");
         }
         RILQUIRKS_V5_LEGACY = false;
         RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = true;
         break;
@@ -2820,16 +2825,22 @@ RIL[REQUEST_GET_SIM_STATUS] = function R
       app_state:      Buf.readUint32(), // CARD_APPSTATE_*
       perso_substate: Buf.readUint32(), // CARD_PERSOSUBSTATE_*
       aid:            Buf.readString(),
       app_label:      Buf.readString(),
       pin1_replaced:  Buf.readUint32(),
       pin1:           Buf.readUint32(),
       pin2:           Buf.readUint32()
     });
+    if (RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS) {
+      Buf.readUint32();
+      Buf.readUint32();
+      Buf.readUint32();
+      Buf.readUint32();
+    }
   }
 
   if (DEBUG) debug("iccStatus: " + JSON.stringify(iccStatus));
   this._processICCStatus(iccStatus);
 };
 RIL[REQUEST_ENTER_SIM_PIN] = function REQUEST_ENTER_SIM_PIN(length, options) {
   this.sendDOMMessage({type: "iccunlockcardlock",
                        lockType: "pin",
--- a/editor/libeditor/base/PlaceholderTxn.cpp
+++ b/editor/libeditor/base/PlaceholderTxn.cpp
@@ -2,17 +2,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PlaceholderTxn.h"
 #include "nsEditor.h"
 #include "IMETextTxn.h"
 #include "nsGkAtoms.h"
-#include "nsISelection.h"
+#include "mozilla/Selection.h"
+
+using namespace mozilla;
 
 PlaceholderTxn::PlaceholderTxn() :  EditAggregateTxn(), 
                                     mAbsorb(true), 
                                     mForwarding(nsnull),
                                     mIMETextTxn(nsnull),
                                     mCommitted(false),
                                     mStartSel(nsnull),
                                     mEndSel(),
@@ -37,17 +39,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTxn)
   NS_INTERFACE_MAP_ENTRY(nsIAbsorbingTransaction)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(EditAggregateTxn)
 
 NS_IMPL_ADDREF_INHERITED(PlaceholderTxn, EditAggregateTxn)
 NS_IMPL_RELEASE_INHERITED(PlaceholderTxn, EditAggregateTxn)
 
-NS_IMETHODIMP PlaceholderTxn::Init(nsIAtom *aName, nsSelectionState *aSelState, nsIEditor *aEditor)
+NS_IMETHODIMP
+PlaceholderTxn::Init(nsIAtom* aName, nsSelectionState* aSelState,
+                     nsEditor* aEditor)
 {
   NS_ENSURE_TRUE(aEditor && aSelState, NS_ERROR_NULL_POINTER);
 
   mName = aName;
   mStartSel = aSelState;
   mEditor = aEditor;
   return NS_OK;
 }
@@ -251,15 +255,14 @@ NS_IMETHODIMP PlaceholderTxn::ForwardEnd
 NS_IMETHODIMP PlaceholderTxn::Commit()
 {
   mCommitted = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP PlaceholderTxn::RememberEndingSelection()
 {
-  nsCOMPtr<nsISelection> selection;
-  nsresult res = mEditor->GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<Selection> selection = mEditor->GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
-  return mEndSel.SaveSelection(selection);
+  mEndSel.SaveSelection(selection);
+  return NS_OK;
 }
 
--- a/editor/libeditor/base/PlaceholderTxn.h
+++ b/editor/libeditor/base/PlaceholderTxn.h
@@ -39,17 +39,18 @@ public:
 
   NS_DECL_EDITTXN
 
   NS_IMETHOD RedoTransaction();
   NS_IMETHOD Merge(nsITransaction *aTransaction, bool *aDidMerge);
 
 // ------------ nsIAbsorbingTransaction -----------------------
 
-  NS_IMETHOD Init(nsIAtom *aName, nsSelectionState *aSelState, nsIEditor *aEditor);
+  NS_IMETHOD Init(nsIAtom* aName, nsSelectionState* aSelState,
+                  nsEditor* aEditor);
   
   NS_IMETHOD GetTxnName(nsIAtom **aName);
   
   NS_IMETHOD StartSelectionEquals(nsSelectionState *aSelState, bool *aResult);
 
   NS_IMETHOD EndPlaceHolderBatch();
 
   NS_IMETHOD ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress);
@@ -67,13 +68,13 @@ protected:
                                 // non-owning for now - can't nsCOMPtr it due to broken transaction interfaces
   bool        mCommitted;       // do we stop auto absorbing any matching placeholder txns?
   // these next two members store the state of the selection in a safe way. 
   // selection at the start of the txn is stored, as is the selection at the end.
   // This is so that UndoTransaction() and RedoTransaction() can restore the
   // selection properly.
   nsAutoPtr<nsSelectionState> mStartSel; // use a pointer because this is constructed before we exist
   nsSelectionState  mEndSel;
-  nsIEditor*        mEditor;   /** the editor for this transaction */
+  nsEditor*         mEditor;   /** the editor for this transaction */
 };
 
 
 #endif
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/base/crashtests/776323.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html contenteditable="true">
+<head>
+<script>
+
+function boom()
+{
+  document.execCommand("inserthtml", false, "b");
+  var myrange = document.createRange();
+  myrange.selectNodeContents(document.getElementsByTagName("img")[0]);
+  window.getSelection().addRange(myrange);
+  document.execCommand("strikethrough", false, null);
+}
+
+</script>
+</head>
+<body onload="boom();"><img></body>
+</html>
--- a/editor/libeditor/base/crashtests/crashtests.list
+++ b/editor/libeditor/base/crashtests/crashtests.list
@@ -12,8 +12,9 @@ load 713427-1.html
 load 713427-2.xhtml
 load 762183.html
 load 766360.html
 load 766413.html
 load 766845.xhtml
 load 768765.html
 needs-focus load 771749.html
 load 772282.html
+load 776323.html
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -899,19 +899,18 @@ nsEditor::BeginPlaceHolderTransaction(ns
 {
   NS_PRECONDITION(mPlaceHolderBatch >= 0, "negative placeholder batch count!");
   if (!mPlaceHolderBatch)
   {
     // time to turn on the batch
     BeginUpdateViewBatch();
     mPlaceHolderTxn = nsnull;
     mPlaceHolderName = aName;
-    nsCOMPtr<nsISelection> selection;
-    nsresult res = GetSelection(getter_AddRefs(selection));
-    if (NS_SUCCEEDED(res)) {
+    nsRefPtr<Selection> selection = GetSelection();
+    if (selection) {
       mSelState = new nsSelectionState();
       mSelState->SaveSelection(selection);
     }
   }
   mPlaceHolderBatch++;
 
   return NS_OK;
 }
@@ -1974,17 +1973,17 @@ nsEditor::DebugUnitTests(PRInt32 *outNum
 
 bool     
 nsEditor::ArePreservingSelection()
 {
   return !(mSavedSel.IsEmpty());
 }
 
 void
-nsEditor::PreserveSelectionAcrossActions(nsISelection *aSel)
+nsEditor::PreserveSelectionAcrossActions(Selection* aSel)
 {
   mSavedSel.SaveSelection(aSel);
   mRangeUpdater.RegisterSelectionState(mSavedSel);
 }
 
 nsresult 
 nsEditor::RestorePreservedSelection(nsISelection *aSel)
 {
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -420,17 +420,17 @@ public:
 
   /** All editor operations which alter the doc should be followed
    *  with a call to EndOperation */
   NS_IMETHOD EndOperation();
 
   /** routines for managing the preservation of selection across 
    *  various editor actions */
   bool     ArePreservingSelection();
-  void     PreserveSelectionAcrossActions(nsISelection *aSel);
+  void     PreserveSelectionAcrossActions(mozilla::Selection* aSel);
   nsresult RestorePreservedSelection(nsISelection *aSel);
   void     StopPreservingSelection();
 
   /** 
    * SplitNode() creates a new node identical to an existing node, and split the contents between the two nodes
    * @param aExistingRightNode   the node to split.  It will become the new node's next sibling.
    * @param aOffset              the offset of aExistingRightNode's content|children to do the split at
    * @param aNewLeftNode         [OUT] the new node resulting from the split, becomes aExistingRightNode's previous sibling.
--- a/editor/libeditor/base/nsEditorUtils.cpp
+++ b/editor/libeditor/base/nsEditorUtils.cpp
@@ -1,46 +1,45 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-
+#include "mozilla/Selection.h"
 #include "nsCOMArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsEditorUtils.h"
 #include "nsError.h"
 #include "nsIClipboardDragDropHookList.h"
 // hooks
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsINode.h"
-#include "nsISelection.h"
 #include "nsISimpleEnumerator.h"
 
 class nsIDOMRange;
 class nsISupports;
 
+using namespace mozilla;
 
 /******************************************************************************
  * nsAutoSelectionReset
  *****************************************************************************/
 
-nsAutoSelectionReset::nsAutoSelectionReset(nsISelection *aSel, nsEditor *aEd) : 
-mSel(nsnull)
-,mEd(nsnull)
+nsAutoSelectionReset::nsAutoSelectionReset(Selection* aSel, nsEditor* aEd)
+  : mSel(nsnull), mEd(nsnull)
 { 
   if (!aSel || !aEd) return;    // not much we can do, bail.
   if (aEd->ArePreservingSelection()) return;   // we already have initted mSavedSel, so this must be nested call.
-  mSel = do_QueryInterface(aSel);
+  mSel = aSel;
   mEd = aEd;
   if (mSel)
   {
     mEd->PreserveSelectionAcrossActions(mSel);
   }
 }
 
 nsAutoSelectionReset::~nsAutoSelectionReset()
--- a/editor/libeditor/base/nsEditorUtils.h
+++ b/editor/libeditor/base/nsEditorUtils.h
@@ -52,22 +52,22 @@ class nsAutoEditBatch : public nsAutoPla
 /***************************************************************************
  * stack based helper class for saving/restoring selection.  Note that this
  * assumes that the nodes involved are still around afterwards!
  */
 class NS_STACK_CLASS nsAutoSelectionReset
 {
   private:
     /** ref-counted reference to the selection that we are supposed to restore */
-    nsCOMPtr<nsISelection> mSel;
+    nsRefPtr<mozilla::Selection> mSel;
     nsEditor *mEd;  // non-owning ref to nsEditor
 
   public:
     /** constructor responsible for remembering all state needed to restore aSel */
-    nsAutoSelectionReset(nsISelection *aSel, nsEditor *aEd);
+    nsAutoSelectionReset(mozilla::Selection* aSel, nsEditor* aEd);
     
     /** destructor restores mSel to its former state */
     ~nsAutoSelectionReset();
 
     /** Abort: cancel selection saver */
     void Abort();
 };
 
--- a/editor/libeditor/base/nsIAbsorbingTransaction.h
+++ b/editor/libeditor/base/nsIAbsorbingTransaction.h
@@ -27,17 +27,18 @@ class nsIAtom;
  * A transaction interface mixin - for transactions that can support. 
  * the placeholder absorbtion idiom. 
  */
 class nsIAbsorbingTransaction  : public nsISupports{
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IABSORBINGTRANSACTION_IID)
 
-  NS_IMETHOD Init(nsIAtom *aName, nsSelectionState *aSelState, nsIEditor *aEditor)=0;
+  NS_IMETHOD Init(nsIAtom* aName, nsSelectionState* aSelState,
+                  nsEditor* aEditor) = 0;
   
   NS_IMETHOD EndPlaceHolderBatch()=0;
   
   NS_IMETHOD GetTxnName(nsIAtom **aName)=0;
 
   NS_IMETHOD StartSelectionEquals(nsSelectionState *aSelState, bool *aResult)=0;
 
   NS_IMETHOD ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress)=0;
--- a/editor/libeditor/base/nsSelectionState.cpp
+++ b/editor/libeditor/base/nsSelectionState.cpp
@@ -1,29 +1,31 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
+#include "mozilla/Selection.h"          // for Selection
 #include "nsAString.h"                  // for nsAString_internal::Length
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsEditor.h"                   // for nsEditor
 #include "nsEditorUtils.h"              // for nsEditorUtils
 #include "nsError.h"                    // for NS_OK, etc
 #include "nsIDOMCharacterData.h"        // for nsIDOMCharacterData
 #include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nsIDOMRange.h"                // for nsIDOMRange, etc
 #include "nsISelection.h"               // for nsISelection
 #include "nsISupportsImpl.h"            // for nsRange::Release
 #include "nsRange.h"                    // for nsRange
 #include "nsSelectionState.h"
 
+using namespace mozilla;
 
 /***************************************************************************
  * class for recording selection info.  stores selection as collection of
  * { {startnode, startoffset} , {endnode, endoffset} } tuples.  Can't store
  * ranges since dom gravity will possibly change the ranges.
  */
 nsSelectionState::nsSelectionState() : mArray(){}
 
@@ -42,53 +44,40 @@ nsSelectionState::DoTraverse(nsCycleColl
                                        "selection state mArray[i].startNode");
     cb.NoteXPCOMChild(item->startNode);
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
                                        "selection state mArray[i].endNode");
     cb.NoteXPCOMChild(item->endNode);
   }
 }
 
-nsresult  
-nsSelectionState::SaveSelection(nsISelection *aSel)
+void
+nsSelectionState::SaveSelection(Selection* aSel)
 {
-  NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
-  PRInt32 i,rangeCount, arrayCount = mArray.Length();
-  aSel->GetRangeCount(&rangeCount);
-  
+  MOZ_ASSERT(aSel);
+  PRInt32 arrayCount = mArray.Length();
+  PRInt32 rangeCount = aSel->GetRangeCount();
+
   // if we need more items in the array, new them
-  if (arrayCount<rangeCount)
-  {
-    PRInt32 count = rangeCount-arrayCount;
-    for (i=0; i<count; i++)
-    {
+  if (arrayCount < rangeCount) {
+    for (PRInt32 i = arrayCount; i < rangeCount; i++) {
       mArray.AppendElement();
       mArray[i] = new nsRangeStore();
     }
-  }
-  
-  // else if we have too many, delete them
-  else if (arrayCount>rangeCount)
-  {
-    for (i = arrayCount-1; i >= rangeCount; i--)
-    {
+  } else if (arrayCount > rangeCount) {
+    // else if we have too many, delete them
+    for (PRInt32 i = arrayCount - 1; i >= rangeCount; i--) {
       mArray.RemoveElementAt(i);
     }
   }
-  
+
   // now store the selection ranges
-  nsresult res = NS_OK;
-  for (i=0; i<rangeCount; i++)
-  {
-    nsCOMPtr<nsIDOMRange> range;
-    res = aSel->GetRangeAt(i, getter_AddRefs(range));
-    mArray[i]->StoreRange(range);
+  for (PRInt32 i = 0; i < rangeCount; i++) {
+    mArray[i]->StoreRange(aSel->GetRangeAt(i));
   }
-  
-  return res;
 }
 
 nsresult  
 nsSelectionState::RestoreSelection(nsISelection *aSel)
 {
   NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
   nsresult res;
   PRUint32 i, arrayCount = mArray.Length();
--- a/editor/libeditor/base/nsSelectionState.h
+++ b/editor/libeditor/base/nsSelectionState.h
@@ -13,16 +13,19 @@
 #include "nscore.h"
 #include "prtypes.h"
 
 class nsCycleCollectionTraversalCallback;
 class nsIDOMCharacterData;
 class nsIDOMRange;
 class nsISelection;
 class nsRange;
+namespace mozilla {
+class Selection;
+}
 
 /***************************************************************************
  * class for recording selection info.  stores selection as collection of
  * { {startnode, startoffset} , {endnode, endoffset} } tuples.  Can't store
  * ranges since dom gravity will possibly change the ranges.
  */
 
 // first a helper struct for saving/setting ranges
@@ -47,17 +50,17 @@ class nsSelectionState
   public:
       
     nsSelectionState();
     ~nsSelectionState();
 
     void DoTraverse(nsCycleCollectionTraversalCallback &cb);
     void DoUnlink() { MakeEmpty(); }
   
-    nsresult SaveSelection(nsISelection *aSel);
+    void     SaveSelection(mozilla::Selection *aSel);
     nsresult RestoreSelection(nsISelection *aSel);
     bool     IsCollapsed();
     bool     IsEqual(nsSelectionState *aSelState);
     void     MakeEmpty();
     bool     IsEmpty();
   protected:    
     nsTArray<nsRefPtr<nsRangeStore> > mArray;
     
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -2864,17 +2864,17 @@ nsHTMLEditRules::DidDeleteSelection(nsIS
     }
   }
   
   // call through to base class
   return nsTextEditRules::DidDeleteSelection(aSelection, aDir, aResult);
 }
 
 nsresult
-nsHTMLEditRules::WillMakeList(nsISelection* aSelection,
+nsHTMLEditRules::WillMakeList(Selection* aSelection,
                               const nsAString* aListType,
                               bool aEntireList,
                               const nsAString* aBulletType,
                               bool* aCancel,
                               bool* aHandled,
                               const nsAString* aItemType)
 {
   if (!aSelection || !aListType || !aCancel || !aHandled) {
@@ -3154,17 +3154,17 @@ nsHTMLEditRules::WillMakeList(nsISelecti
     }
   }
 
   return res;
 }
 
 
 nsresult
-nsHTMLEditRules::WillRemoveList(nsISelection *aSelection, 
+nsHTMLEditRules::WillRemoveList(Selection* aSelection,
                                 bool aOrdered, 
                                 bool *aCancel,
                                 bool *aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   // initialize out param
   *aCancel = false;
   *aHandled = true;
@@ -3221,29 +3221,29 @@ nsHTMLEditRules::WillRemoveList(nsISelec
       NS_ENSURE_SUCCESS(res, res);
     }
   }
   return res;
 }
 
 
 nsresult
-nsHTMLEditRules::WillMakeDefListItem(nsISelection *aSelection, 
+nsHTMLEditRules::WillMakeDefListItem(Selection* aSelection,
                                      const nsAString *aItemType, 
                                      bool aEntireList, 
                                      bool *aCancel,
                                      bool *aHandled)
 {
   // for now we let WillMakeList handle this
   NS_NAMED_LITERAL_STRING(listType, "dl");
   return WillMakeList(aSelection, &listType, aEntireList, nsnull, aCancel, aHandled, aItemType);
 }
 
 nsresult
-nsHTMLEditRules::WillMakeBasicBlock(nsISelection *aSelection, 
+nsHTMLEditRules::WillMakeBasicBlock(Selection* aSelection,
                                     const nsAString *aBlockType, 
                                     bool *aCancel,
                                     bool *aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   // initialize out param
   *aCancel = false;
   *aHandled = false;
@@ -3390,30 +3390,32 @@ nsHTMLEditRules::DidMakeBasicBlock(nsISe
   PRInt32 offset;
   nsresult res = nsEditor::GetStartNodeAndOffset(aSelection, getter_AddRefs(parent), &offset);
   NS_ENSURE_SUCCESS(res, res);
   res = InsertMozBRIfNeeded(parent);
   return res;
 }
 
 nsresult
-nsHTMLEditRules::WillIndent(nsISelection *aSelection, bool *aCancel, bool * aHandled)
+nsHTMLEditRules::WillIndent(Selection* aSelection,
+                            bool* aCancel, bool* aHandled)
 {
   nsresult res;
   if (mHTMLEditor->IsCSSEnabled()) {
     res = WillCSSIndent(aSelection, aCancel, aHandled);
   }
   else {
     res = WillHTMLIndent(aSelection, aCancel, aHandled);
   }
   return res;
 }
 
 nsresult
-nsHTMLEditRules::WillCSSIndent(nsISelection *aSelection, bool *aCancel, bool * aHandled)
+nsHTMLEditRules::WillCSSIndent(Selection* aSelection,
+                               bool* aCancel, bool* aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   
   nsresult res = WillInsert(aSelection, aCancel);
   NS_ENSURE_SUCCESS(res, res);
 
   // initialize out param
   // we want to ignore result of WillInsert()
@@ -3609,17 +3611,18 @@ nsHTMLEditRules::WillCSSIndent(nsISelect
         NS_ENSURE_SUCCESS(res, res);
       }
     }
   }
   return res;
 }
 
 nsresult
-nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, bool *aCancel, bool * aHandled)
+nsHTMLEditRules::WillHTMLIndent(Selection* aSelection,
+                                bool* aCancel, bool* aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   nsresult res = WillInsert(aSelection, aCancel);
   NS_ENSURE_SUCCESS(res, res);
 
   // initialize out param
   // we want to ignore result of WillInsert()
   *aCancel = false;
@@ -3837,17 +3840,18 @@ nsHTMLEditRules::WillHTMLIndent(nsISelec
       }
     }
   }
   return res;
 }
 
 
 nsresult
-nsHTMLEditRules::WillOutdent(nsISelection *aSelection, bool *aCancel, bool *aHandled)
+nsHTMLEditRules::WillOutdent(Selection* aSelection,
+                             bool* aCancel, bool* aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   // initialize out param
   *aCancel = false;
   *aHandled = true;
   nsresult res = NS_OK;
   nsCOMPtr<nsIDOMNode> rememberedLeftBQ, rememberedRightBQ;
   bool useCSS = mHTMLEditor->IsCSSEnabled();
@@ -4407,17 +4411,17 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode
 
   NS_ENSURE_TRUE(nodeToTest, NS_ERROR_NULL_POINTER);
   return mHTMLEditor->IsEmptyNode(nodeToTest, outIsEmptyBlock,
                      aMozBRDoesntCount, aListItemsNotEmpty);
 }
 
 
 nsresult
-nsHTMLEditRules::WillAlign(nsISelection *aSelection, 
+nsHTMLEditRules::WillAlign(Selection* aSelection,
                            const nsAString *alignType, 
                            bool *aCancel,
                            bool *aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
 
   nsresult res = WillInsert(aSelection, aCancel);
   NS_ENSURE_SUCCESS(res, res);
@@ -8565,17 +8569,18 @@ nsHTMLEditRules::RelativeChangeIndentati
   return mHTMLEditor->RemoveContainer(element);
 }
 
 //
 // Support for Absolute Positioning
 //
 
 nsresult
-nsHTMLEditRules::WillAbsolutePosition(nsISelection *aSelection, bool *aCancel, bool * aHandled)
+nsHTMLEditRules::WillAbsolutePosition(Selection* aSelection,
+                                      bool* aCancel, bool* aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   nsresult res = WillInsert(aSelection, aCancel);
   NS_ENSURE_SUCCESS(res, res);
 
   // initialize out param
   // we want to ignore result of WillInsert()
   *aCancel = false;
@@ -8781,18 +8786,18 @@ nsresult
 nsHTMLEditRules::DidAbsolutePosition()
 {
   nsCOMPtr<nsIHTMLAbsPosEditor> absPosHTMLEditor = mHTMLEditor;
   nsCOMPtr<nsIDOMElement> elt = do_QueryInterface(mNewBlock);
   return absPosHTMLEditor->AbsolutelyPositionElement(elt, true);
 }
 
 nsresult
-nsHTMLEditRules::WillRemoveAbsolutePosition(nsISelection *aSelection, bool *aCancel, bool * aHandled)
-{
+nsHTMLEditRules::WillRemoveAbsolutePosition(Selection* aSelection,
+                                            bool* aCancel, bool* aHandled) {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   nsresult res = WillInsert(aSelection, aCancel);
   NS_ENSURE_SUCCESS(res, res);
 
   // initialize out param
   // we want to ignore aCancel from WillInsert()
   *aCancel = false;
   *aHandled = true;
@@ -8803,17 +8808,17 @@ nsHTMLEditRules::WillRemoveAbsolutePosit
 
   nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
 
   nsCOMPtr<nsIHTMLAbsPosEditor> absPosHTMLEditor = mHTMLEditor;
   return absPosHTMLEditor->AbsolutelyPositionElement(elt, false);
 }
 
 nsresult
-nsHTMLEditRules::WillRelativeChangeZIndex(nsISelection *aSelection,
+nsHTMLEditRules::WillRelativeChangeZIndex(Selection* aSelection,
                                           PRInt32 aChange,
                                           bool *aCancel,
                                           bool * aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
   nsresult res = WillInsert(aSelection, aCancel);
   NS_ENSURE_SUCCESS(res, res);
 
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -151,28 +151,48 @@ protected:
   nsresult InsertBRIfNeeded(nsISelection *aSelection);
   nsresult GetGoodSelPointForNode(nsIDOMNode *aNode, nsIEditor::EDirection aAction, 
                                   nsCOMPtr<nsIDOMNode> *outSelNode, PRInt32 *outSelOffset);
   nsresult JoinBlocks(nsCOMPtr<nsIDOMNode> *aLeftBlock, nsCOMPtr<nsIDOMNode> *aRightBlock, bool *aCanceled);
   nsresult MoveBlock(nsIDOMNode *aLeft, nsIDOMNode *aRight, PRInt32 aLeftOffset, PRInt32 aRightOffset);
   nsresult MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, PRInt32 *aOffset);
   nsresult MoveContents(nsIDOMNode *aSource, nsIDOMNode *aDest, PRInt32 *aOffset);
   nsresult DeleteNonTableElements(nsINode* aNode);
-  nsresult WillMakeList(nsISelection *aSelection, const nsAString *aListType, bool aEntireList, const nsAString *aBulletType, bool *aCancel, bool *aHandled, const nsAString *aItemType=nsnull);
-  nsresult WillRemoveList(nsISelection *aSelection, bool aOrderd, bool *aCancel, bool *aHandled);
-  nsresult WillIndent(nsISelection *aSelection, bool *aCancel, bool *aHandled);
-  nsresult WillCSSIndent(nsISelection *aSelection, bool *aCancel, bool *aHandled);
-  nsresult WillHTMLIndent(nsISelection *aSelection, bool *aCancel, bool *aHandled);
-  nsresult WillOutdent(nsISelection *aSelection, bool *aCancel, bool *aHandled);
-  nsresult WillAlign(nsISelection *aSelection, const nsAString *alignType, bool *aCancel, bool *aHandled);
-  nsresult WillAbsolutePosition(nsISelection *aSelection, bool *aCancel, bool * aHandled);
-  nsresult WillRemoveAbsolutePosition(nsISelection *aSelection, bool *aCancel, bool * aHandled);
-  nsresult WillRelativeChangeZIndex(nsISelection *aSelection, PRInt32 aChange, bool *aCancel, bool * aHandled);
-  nsresult WillMakeDefListItem(nsISelection *aSelection, const nsAString *aBlockType, bool aEntireList, bool *aCancel, bool *aHandled);
-  nsresult WillMakeBasicBlock(nsISelection *aSelection, const nsAString *aBlockType, bool *aCancel, bool *aHandled);
+  nsresult WillMakeList(mozilla::Selection* aSelection,
+                        const nsAString* aListType,
+                        bool aEntireList,
+                        const nsAString* aBulletType,
+                        bool* aCancel, bool* aHandled,
+                        const nsAString* aItemType = nsnull);
+  nsresult WillRemoveList(mozilla::Selection* aSelection,
+                          bool aOrdered, bool* aCancel, bool* aHandled);
+  nsresult WillIndent(mozilla::Selection* aSelection,
+                      bool* aCancel, bool* aHandled);
+  nsresult WillCSSIndent(mozilla::Selection* aSelection,
+                         bool* aCancel, bool* aHandled);
+  nsresult WillHTMLIndent(mozilla::Selection* aSelection,
+                          bool* aCancel, bool* aHandled);
+  nsresult WillOutdent(mozilla::Selection* aSelection,
+                       bool* aCancel, bool* aHandled);
+  nsresult WillAlign(mozilla::Selection* aSelection,
+                     const nsAString* alignType,
+                     bool* aCancel, bool* aHandled);
+  nsresult WillAbsolutePosition(mozilla::Selection* aSelection,
+                                bool* aCancel, bool* aHandled);
+  nsresult WillRemoveAbsolutePosition(mozilla::Selection* aSelection,
+                                      bool* aCancel, bool* aHandled);
+  nsresult WillRelativeChangeZIndex(mozilla::Selection* aSelection,
+                                    PRInt32 aChange,
+                                    bool* aCancel, bool* aHandled);
+  nsresult WillMakeDefListItem(mozilla::Selection* aSelection,
+                               const nsAString* aBlockType, bool aEntireList,
+                               bool* aCancel, bool* aHandled);
+  nsresult WillMakeBasicBlock(mozilla::Selection* aSelection,
+                              const nsAString* aBlockType,
+                              bool* aCancel, bool* aHandled);
   nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
   nsresult DidAbsolutePosition();
   nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsAString *alignType);
   nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType);
   nsresult AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
                                   nsINode* aNode);
   nsresult AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
                                   nsIDOMNode *aNode);
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -3374,25 +3374,23 @@ SetSelectionAroundHeadChildren(nsISelect
   // Then extend it to just after.
   PRUint32 childCount = headNode->GetChildCount();
   return aSelection->ExtendNative(headNode, childCount + 1);
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::GetHeadContentsAsHTML(nsAString& aOutputString)
 {
-  nsCOMPtr<nsISelection> selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   // Save current selection
   nsAutoSelectionReset selectionResetter(selection, this);
 
-  res = SetSelectionAroundHeadChildren(selection, mDocWeak);
+  nsresult res = SetSelectionAroundHeadChildren(selection, mDocWeak);
   NS_ENSURE_SUCCESS(res, res);
 
   res = OutputToString(NS_LITERAL_STRING("text/html"),
                        nsIDocumentEncoder::OutputSelectionOnly,
                        aOutputString);
   if (NS_SUCCEEDED(res))
   {
     // Selection always includes <body></body>,
--- a/editor/libeditor/html/nsHTMLEditorStyle.cpp
+++ b/editor/libeditor/html/nsHTMLEditorStyle.cpp
@@ -1530,36 +1530,33 @@ nsHTMLEditor::RelativeFontChange( PRInt3
 {
   // Can only change font size by + or - 1
   if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
     return NS_ERROR_ILLEGAL_VALUE;
   
   ForceCompositionEnd();
 
   // Get the selection 
-  nsCOMPtr<nsISelection>selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
-  nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));  
   // Is the selection collapsed?
   // if it's collapsed set typing state
   if (selection->Collapsed()) {
     nsCOMPtr<nsIAtom> atom;
     if (aSizeChange==1) atom = nsEditProperty::big;
     else                atom = nsEditProperty::small;
 
     // Let's see in what kind of element the selection is
     PRInt32 offset;
     nsCOMPtr<nsIDOMNode> selectedNode;
     GetStartNodeAndOffset(selection, getter_AddRefs(selectedNode), &offset);
     NS_ENSURE_TRUE(selectedNode, NS_OK);
     if (IsTextNode(selectedNode)) {
       nsCOMPtr<nsIDOMNode> parent;
-      res = selectedNode->GetParentNode(getter_AddRefs(parent));
+      nsresult res = selectedNode->GetParentNode(getter_AddRefs(parent));
       NS_ENSURE_SUCCESS(res, res);
       selectedNode = parent;
     }
     if (!CanContainTag(selectedNode, atom)) {
       return NS_OK;
     }
 
     // manipulating text attributes on a collapsed selection only sets state for the next text insertion
@@ -1570,17 +1567,17 @@ nsHTMLEditor::RelativeFontChange( PRInt3
   // wrap with txn batching, rules sniffing, and selection preservation code
   nsAutoEditBatch batchIt(this);
   nsAutoRules beginRulesSniffing(this, kOpSetTextProperty, nsIEditor::eNext);
   nsAutoSelectionReset selectionResetter(selection, this);
   nsAutoTxnsConserveSelection dontSpazMySelection(this);
 
   // get selection range enumerator
   nsCOMPtr<nsIEnumerator> enumerator;
-  res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
+  nsresult res = selection->GetEnumerator(getter_AddRefs(enumerator));
   NS_ENSURE_SUCCESS(res, res);
   NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
 
   // loop thru the ranges in the selection
   enumerator->First(); 
   nsCOMPtr<nsISupports> currentItem;
   while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
   {
--- a/editor/libeditor/html/nsTableEditor.cpp
+++ b/editor/libeditor/html/nsTableEditor.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdio.h>
 
 #include "mozilla/Assertions.h"
+#include "mozilla/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsEditProperty.h"
 #include "nsEditor.h"
 #include "nsEditorUtils.h"
@@ -23,18 +24,16 @@
 #include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMRange.h"
 #include "nsIEditor.h"
 #include "nsIFrame.h"
 #include "nsIHTMLEditor.h"
 #include "nsINode.h"
 #include "nsIPresShell.h"
-#include "nsISelection.h"
-#include "nsISelectionPrivate.h"  // For nsISelectionPrivate::TABLESELECTION_ defines
 #include "nsISupportsUtils.h"
 #include "nsITableCellLayout.h" // For efficient access to table cell
 #include "nsITableEditor.h"
 #include "nsITableLayout.h"     //  data owned by the table and cell frames
 #include "nsLayoutErrors.h"
 #include "nsLiteralString.h"
 #include "nsQueryFrame.h"
 #include "nsString.h"
@@ -1948,29 +1947,28 @@ nsHTMLEditor::SwitchTableCellHeaderType(
   // Prevent auto insertion of BR in new cell created by ReplaceContainer
   nsAutoRules beginRulesSniffing(this, kOpInsertNode, nsIEditor::eNext);
 
   nsCOMPtr<nsIDOMNode> newNode;
 
   // Save current selection to restore when done
   // This is needed so ReplaceContainer can monitor selection
   //  when replacing nodes
-  nsCOMPtr<nsISelection>selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
   nsAutoSelectionReset selectionResetter(selection, this);
 
   // Set to the opposite of current type
   nsCOMPtr<nsIAtom> atom = nsEditor::GetTag(aSourceCell);
   nsString newCellType( (atom == nsEditProperty::td) ? NS_LITERAL_STRING("th") : NS_LITERAL_STRING("td"));
 
   // This creates new node, moves children, copies attributes (true)
   //   and manages the selection!
-  res = ReplaceContainer(aSourceCell, address_of(newNode), newCellType, nsnull, nsnull, true);
+  nsresult res = ReplaceContainer(aSourceCell, address_of(newNode),
+                                  newCellType, nsnull, nsnull, true);
   NS_ENSURE_SUCCESS(res, res);
   NS_ENSURE_TRUE(newNode, NS_ERROR_FAILURE);
 
   // Return the new cell
   if (aNewCell)
   {
     nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newNode);
     *aNewCell = newElement.get();
@@ -2486,23 +2484,22 @@ nsHTMLEditor::FixBadColSpan(nsIDOMElemen
     }
   }
   return GetTableSize(aTable, &rowCount, &aNewColCount);
 }
 
 NS_IMETHODIMP 
 nsHTMLEditor::NormalizeTable(nsIDOMElement *aTable)
 {
-  nsCOMPtr<nsISelection>selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDOMElement> table;
-  res = GetElementOrParentByTagName(NS_LITERAL_STRING("table"), aTable, getter_AddRefs(table));
+  nsresult res = GetElementOrParentByTagName(NS_LITERAL_STRING("table"),
+                                             aTable, getter_AddRefs(table));
   NS_ENSURE_SUCCESS(res, res);
   // Don't fail if we didn't find a table
   NS_ENSURE_TRUE(table, NS_OK);
 
   PRInt32 rowCount, colCount, rowIndex, colIndex;
   res = GetTableSize(table, &rowCount, &colCount);
   NS_ENSURE_SUCCESS(res, res);
 
--- a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
@@ -579,16 +579,23 @@ nsDocShellTreeOwner::GetParentNativeWind
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
 {
   return NS_ERROR_NULL_POINTER;
 }
 
 NS_IMETHODIMP
+nsDocShellTreeOwner::GetNativeHandle(nsAString& aNativeHandle)
+{
+  // the nativeHandle should be accessed from nsIXULWindow
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsDocShellTreeOwner::GetVisibility(bool* aVisibility)
 {
   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   if (ownerWin)
   {
     return ownerWin->GetVisibility(aVisibility);
   }
   return NS_ERROR_NULL_POINTER;
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -1373,16 +1373,22 @@ NS_IMETHODIMP nsWebBrowser::SetParentNat
 {
    NS_ENSURE_STATE(!mDocShell);
 
    mParentNativeWindow = aParentNativeWindow;
 
    return NS_OK;
 }
 
+NS_IMETHODIMP nsWebBrowser::GetNativeHandle(nsAString& aNativeHandle)
+{
+   // the nativeHandle should be accessed from nsIXULWindow
+   return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 NS_IMETHODIMP nsWebBrowser::GetVisibility(bool* visibility)
 {
    NS_ENSURE_ARG_POINTER(visibility);
 
    if(!mDocShell)
       *visibility = mInitInfo->visible;
    else
       NS_ENSURE_SUCCESS(mDocShellAsWin->GetVisibility(visibility), NS_ERROR_FAILURE);
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -298,21 +298,23 @@ nsPermissionManager::Init()
 
   return NS_OK;
 }
 
 nsresult
 nsPermissionManager::InitDB(bool aRemoveFile)
 {
   nsCOMPtr<nsIFile> permissionsFile;
-  NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(permissionsFile));
-  if (!permissionsFile)
-    return NS_ERROR_UNEXPECTED;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_PERMISSION_PARENT_DIR, getter_AddRefs(permissionsFile));
+  if (NS_FAILED(rv)) {
+    rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(permissionsFile));
+  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
-  nsresult rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(kPermissionsFileName));
+  rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(kPermissionsFileName));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aRemoveFile) {
     bool exists = false;
     rv = permissionsFile->Exists(&exists);
     NS_ENSURE_SUCCESS(rv, rv);
     if (exists) {
       rv = permissionsFile->Remove(false);
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -17,16 +17,17 @@
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"
 
 #include "BasicTiledThebesLayer.h"
 #include "BasicLayersImpl.h"
 #include "BasicThebesLayer.h"
 #include "BasicContainerLayer.h"
 #include "mozilla/Preferences.h"
+#include "nsIWidget.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 /**
  * Clips to the smallest device-pixel-aligned rectangle containing aRect
@@ -127,17 +128,18 @@ BasicLayerManager::~BasicLayerManager()
 
   mRoot = nsnull;
 
   MOZ_COUNT_DTOR(BasicLayerManager);
 }
 
 void
 BasicLayerManager::SetDefaultTarget(gfxContext* aContext,
-                                    BufferMode aDoubleBuffering)
+                                    BufferMode aDoubleBuffering,
+                                    ScreenRotation aRotation)
 {
   NS_ASSERTION(!InTransaction(),
                "Must set default target outside transaction");
   mDefaultTarget = aContext;
   mDoubleBuffering = aDoubleBuffering;
 }
 
 void
@@ -917,17 +919,17 @@ already_AddRefed<ReadbackLayer>
 BasicLayerManager::CreateReadbackLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ReadbackLayer> layer = new BasicReadbackLayer(this);
   return layer.forget();
 }
 
 BasicShadowLayerManager::BasicShadowLayerManager(nsIWidget* aWidget) :
-  BasicLayerManager(aWidget)
+  BasicLayerManager(aWidget), mTargetRotation(ROTATION_0)
 {
   MOZ_COUNT_CTOR(BasicShadowLayerManager);
 }
 
 BasicShadowLayerManager::~BasicShadowLayerManager()
 {
   MOZ_COUNT_DTOR(BasicShadowLayerManager);
 }
@@ -938,16 +940,28 @@ BasicShadowLayerManager::GetMaxTextureSi
   if (HasShadowManager()) {
     return ShadowLayerForwarder::GetMaxTextureSize();
   }
 
   return PR_INT32_MAX;
 }
 
 void
+BasicShadowLayerManager::SetDefaultTarget(gfxContext* aContext,
+                                          BufferMode aDoubleBuffering,
+                                          ScreenRotation aRotation)
+{
+  BasicLayerManager::SetDefaultTarget(aContext, aDoubleBuffering, aRotation);
+  mTargetRotation = aRotation;
+  if (mWidget) {
+    mTargetBounds = mWidget->GetNaturalBounds();
+  }
+}
+
+void
 BasicShadowLayerManager::SetRoot(Layer* aLayer)
 {
   if (mRoot != aLayer) {
     if (HasShadowManager()) {
       // Have to hold the old root and its children in order to
       // maintain the same view of the layer tree in this process as
       // the parent sees.  Otherwise layers can be destroyed
       // mid-transaction and bad things can happen (v. bug 612573)
@@ -976,17 +990,17 @@ BasicShadowLayerManager::BeginTransactio
 {
   NS_ABORT_IF_FALSE(mKeepAlive.IsEmpty(), "uncommitted txn?");
   nsRefPtr<gfxContext> targetContext = aTarget;
 
   // If the last transaction was incomplete (a failed DoEmptyTransaction),
   // don't signal a new transaction to ShadowLayerForwarder. Carry on adding
   // to the previous transaction.
   if (HasShadowManager()) {
-    ShadowLayerForwarder::BeginTransaction();
+    ShadowLayerForwarder::BeginTransaction(mTargetBounds, mTargetRotation);
 
     // If we have a non-default target, we need to let our shadow manager draw
     // to it. This will happen at the end of the transaction.
     if (aTarget && (aTarget != mDefaultTarget) &&
         XRE_GetProcessType() == GeckoProcessType_Default) {
       mShadowTarget = aTarget;
 
       // Create a temporary target for ourselves, so that mShadowTarget is only
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -5,21 +5,21 @@
 
 #ifndef GFX_BASICLAYERS_H
 #define GFX_BASICLAYERS_H
 
 #include "Layers.h"
 
 #include "gfxContext.h"
 #include "gfxCachedTempSurface.h"
+#include "mozilla/layers/ShadowLayers.h"
+#include "mozilla/WidgetUtils.h"
 #include "nsAutoRef.h"
 #include "nsThreadUtils.h"
 
-#include "mozilla/layers/ShadowLayers.h"
-
 class nsIWidget;
 
 namespace mozilla {
 namespace layers {
 
 class BasicShadowableLayer;
 class ShadowThebesLayer;
 class ShadowContainerLayer;
@@ -75,17 +75,18 @@ public:
    * results, by using a temporary buffer when necessary. In BUFFERED
    * mode we always completely overwrite the contents of aContext's
    * destination surface (within the clip region) using OPERATOR_SOURCE.
    */
   enum BufferMode {
     BUFFER_NONE,
     BUFFER_BUFFERED
   };
-  void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering);
+  virtual void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering,
+                                ScreenRotation aRotation);
   gfxContext* GetDefaultTarget() { return mDefaultTarget; }
 
   nsIWidget* GetRetainerWidget() { return mWidget; }
   void ClearRetainerWidget() { mWidget = nsnull; }
 
   virtual bool IsWidgetLayerManager() { return mWidget != nsnull; }
 
   virtual void BeginTransaction();
@@ -216,16 +217,18 @@ public:
   }
   virtual ShadowLayerManager* AsShadowManager()
   {
     return this;
   }
 
   virtual PRInt32 GetMaxTextureSize() const;
 
+  virtual void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering,
+                                ScreenRotation aRotation) MOZ_OVERRIDE;
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
   virtual bool EndEmptyTransaction();
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
 
   virtual void SetRoot(Layer* aLayer);
 
@@ -256,21 +259,30 @@ public:
   void SetRepeatTransaction() { mRepeatTransaction = true; }
 
 private:
   /**
    * Forward transaction results to the parent context.
    */
   void ForwardTransaction();
 
+  // The bounds of |mTarget| in device pixels.
+  nsIntRect mTargetBounds;
+
+  LayerRefArray mKeepAlive;
+
+  // Sometimes we draw to targets that don't natively support
+  // landscape/portrait orientation.  When we need to implement that
+  // ourselves, |mTargetRotation| describes the induced transform we
+  // need to apply when compositing content to our target.
+  ScreenRotation mTargetRotation;
+
   // Used to repeat the transaction right away (to avoid rebuilding
   // a display list) to support progressive drawing.
   bool mRepeatTransaction;
-
-  LayerRefArray mKeepAlive;
 };
 
 class BasicShadowableThebesLayer;
 class BasicShadowableLayer : public ShadowableLayer
 {
 public:
   BasicShadowableLayer()
   {
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -15,16 +15,17 @@
 
 #include "ContainerLayerD3D10.h"
 #include "ThebesLayerD3D10.h"
 #include "ColorLayerD3D10.h"
 #include "CanvasLayerD3D10.h"
 #include "ReadbackLayerD3D10.h"
 #include "ImageLayerD3D10.h"
 #include "mozilla/layers/PLayerChild.h"
+#include "mozilla/WidgetUtils.h"
 
 #include "../d3d9/Nv3DVUtils.h"
 
 #include "gfxCrashReporterUtils.h"
 
 using namespace std;
 using namespace mozilla::gfx;
 
@@ -443,17 +444,16 @@ LayerManagerD3D10::CreateOptimalSurface(
        aFormat != gfxASurface::ImageFormatARGB32)) {
     return LayerManager::CreateOptimalSurface(aSize, aFormat);
   }
 
   nsRefPtr<ID3D10Texture2D> texture;
   
   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
   desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
-  desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
   
   HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(texture));
 
   if (FAILED(hr)) {
     NS_WARNING("Failed to create new texture for CreateOptimalSurface!");
     return LayerManager::CreateOptimalSurface(aSize, aFormat);
   }
 
@@ -724,17 +724,18 @@ LayerManagerD3D10::Render()
   }
   device()->RSSetScissorRects(1, &r);
 
   static_cast<LayerD3D10*>(mRoot->ImplData())->RenderLayer();
 
   if (mTarget) {
     PaintToTarget();
   } else if (mBackBuffer) {
-    ShadowLayerForwarder::BeginTransaction();
+    ShadowLayerForwarder::BeginTransaction(mWidget->GetNaturalBounds(),
+                                           ROTATION_0);
     
     nsIntRect contentRect = nsIntRect(0, 0, rect.width, rect.height);
     if (!mRootForShadowTree) {
         mRootForShadowTree = new DummyRoot(this);
         mRootForShadowTree->SetShadow(ConstructShadowFor(mRootForShadowTree));
         CreatedContainerLayer(mRootForShadowTree);
         ShadowLayerForwarder::SetRoot(mRootForShadowTree);
     }
--- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp
@@ -465,17 +465,16 @@ ThebesLayerD3D10::CreateNewTextures(cons
 {
   if (aSize.width == 0 || aSize.height == 0) {
     // Nothing to do.
     return;
   }
 
   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
   desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
-  desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
   HRESULT hr;
 
   if (!mTexture) {
     hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
 
     if (FAILED(hr)) {
       NS_WARNING("Failed to create new texture for ThebesLayerD3D10!");
       return;
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -417,16 +417,23 @@ CompositorParent::Composite()
 
   bool requestNextFrame = TransformShadowTree(mLastCompose);
   if (requestNextFrame) {
     ScheduleComposition();
   }
 
   RenderTraceLayers(aLayer, "0000");
 
+  if (LAYERS_OPENGL == mLayerManager->GetBackendType() &&
+      !mTargetConfig.naturalBounds().IsEmpty()) {
+    LayerManagerOGL* lm = static_cast<LayerManagerOGL*>(mLayerManager.get());
+    lm->SetWorldTransform(
+      ComputeGLTransformForRotation(mTargetConfig.naturalBounds(),
+                                    mTargetConfig.rotation()));
+  }
   mLayerManager->EndEmptyTransaction();
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   if (mExpectedComposeTime + TimeDuration::FromMilliseconds(15) < TimeStamp::Now()) {
     printf_stderr("Compositor: Composite took %i ms.\n",
                   15 + (int)(TimeStamp::Now() - mExpectedComposeTime).ToMilliseconds());
   }
 #endif
@@ -689,18 +696,20 @@ CompositorParent::SyncViewportInfo(const
 #ifdef MOZ_WIDGET_ANDROID
   AndroidBridge::Bridge()->SyncViewportInfo(aDisplayPort, aDisplayResolution, aLayersUpdated,
                                             aScrollOffset, aScaleX, aScaleY);
 #endif
 }
 
 void
 CompositorParent::ShadowLayersUpdated(ShadowLayersParent* aLayerTree,
+                                      const TargetConfig& aTargetConfig,
                                       bool isFirstPaint)
 {
+  mTargetConfig = aTargetConfig;
   mIsFirstPaint = mIsFirstPaint || isFirstPaint;
   mLayersUpdated = true;
   Layer* root = aLayerTree->GetRoot();
   mLayerManager->SetRoot(root);
   if (root) {
     SetShadowProperties(root);
   }
   ScheduleComposition();
@@ -893,16 +902,17 @@ public:
 
   virtual PLayersParent* AllocPLayers(const LayersBackend& aBackendType,
                                       const uint64_t& aId,
                                       LayersBackend* aBackend,
                                       int32_t* aMaxTextureSize) MOZ_OVERRIDE;
   virtual bool DeallocPLayers(PLayersParent* aLayers) MOZ_OVERRIDE;
 
   virtual void ShadowLayersUpdated(ShadowLayersParent* aLayerTree,
+                                   const TargetConfig& aTargetConfig,
                                    bool isFirstPaint) MOZ_OVERRIDE;
 
 private:
   void DeferredDestroy();
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
   // ourself.  This is released (deferred) in ActorDestroy().
@@ -992,18 +1002,20 @@ CrossProcessCompositorParent::DeallocPLa
 {
   ShadowLayersParent* slp = static_cast<ShadowLayersParent*>(aLayers);
   RemoveIndirectTree(slp->GetId());
   delete aLayers;
   return true;
 }
 
 void
-CrossProcessCompositorParent::ShadowLayersUpdated(ShadowLayersParent* aLayerTree,
-                                                  bool isFirstPaint)
+CrossProcessCompositorParent::ShadowLayersUpdated(
+  ShadowLayersParent* aLayerTree,
+  const TargetConfig& aTargetConfig,
+  bool isFirstPaint)
 {
   uint64_t id = aLayerTree->GetId();
   MOZ_ASSERT(id != 0);
   Layer* shadowRoot = aLayerTree->GetRoot();
   if (shadowRoot) {
     SetShadowProperties(shadowRoot);
   }
   UpdateIndirectTree(id, shadowRoot, isFirstPaint);
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -65,16 +65,17 @@ public:
   virtual ~CompositorParent();
 
   virtual bool RecvWillStop() MOZ_OVERRIDE;
   virtual bool RecvStop() MOZ_OVERRIDE;
   virtual bool RecvPause() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
 
   virtual void ShadowLayersUpdated(ShadowLayersParent* aLayerTree,
+                                   const TargetConfig& aTargetConfig,
                                    bool isFirstPaint) MOZ_OVERRIDE;
   void Destroy();
 
   LayerManager* GetLayerManager() { return mLayerManager; }
 
   void SetTransformation(float aScale, nsIntPoint aScrollOffset);
   void AsyncRender();
 
@@ -222,16 +223,17 @@ private:
    * fixed position layers remain in the same position.
    */
   void TransformFixedLayers(Layer* aLayer,
                             const gfxPoint& aTranslation,
                             const gfxPoint& aScaleDiff);
 
   nsRefPtr<LayerManager> mLayerManager;
   nsIWidget* mWidget;
+  TargetConfig mTargetConfig;
   CancelableTask *mCurrentCompositeTask;
   TimeStamp mLastCompose;
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp mExpectedComposeTime;
 #endif
 
   bool mPaused;
   float mXScale;
--- a/gfx/layers/ipc/GeckoContentController.h
+++ b/gfx/layers/ipc/GeckoContentController.h
@@ -17,16 +17,16 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoContentController)
 
   /**
    * Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
    * Implementations per-platform are responsible for actually handling this.
    */
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
 
-  GeckoContentController() {};
-  virtual ~GeckoContentController() {};
+  GeckoContentController() {}
+  virtual ~GeckoContentController() {}
 };
 
 }
 }
 
 #endif // mozilla_layers_GeckoContentController_h
--- a/gfx/layers/ipc/PLayers.ipdl
+++ b/gfx/layers/ipc/PLayers.ipdl
@@ -1,34 +1,41 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=8 et :
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include LayersSurfaces;
+using mozilla::ScreenRotation;
 include protocol PCompositor;
 include protocol PGrallocBuffer;
 include protocol PLayer;
 include protocol PRenderFrame;
 
 include "gfxipc/ShadowLayerUtils.h";
+include "mozilla/WidgetUtils.h";
 
 /**
  * The layers protocol is spoken between thread contexts that manage
  * layer (sub)trees.  The protocol comprises atomically publishing
  * layer subtrees to a "shadow" thread context (which grafts the
  * subtree into its own tree), and atomically updating a published
  * subtree.  ("Atomic" in this sense is wrt painting.)
  */
 
 namespace mozilla {
 namespace layers {
 
+struct TargetConfig {
+  nsIntRect naturalBounds;
+  ScreenRotation rotation;
+};
+
 // Create a shadow layer for |layer|
 struct OpCreateThebesLayer     { PLayer layer; };
 struct OpCreateContainerLayer  { PLayer layer; };
 struct OpCreateImageLayer      { PLayer layer; };
 struct OpCreateColorLayer      { PLayer layer; };
 struct OpCreateCanvasLayer     { PLayer layer; };
 struct OpCreateRefLayer        { PLayer layer; };
 
@@ -186,24 +193,24 @@ parent:
    * is returned.
    */
   sync PGrallocBuffer(gfxIntSize size, gfxContentType content)
     returns (MaybeMagicGrallocBufferHandle handle);
   async PLayer();
 
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
-  sync Update(Edit[] cset, bool isFirstPaint)
+  sync Update(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint)
     returns (EditReply[] reply);
 
   // Composite the layer tree to the given surface, and return the surface.
   sync DrawToSurface(SurfaceDescriptor surfaceIn)
     returns (SurfaceDescriptor surfaceOut);
 
   // We don't need to send a sync transaction if
   // no transaction operate require a swap.
-  async UpdateNoSwap(Edit[] cset, bool isFirstPaint);
+  async UpdateNoSwap(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint);
 
   async __delete__();
 };
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayerUtils.h
+++ b/gfx/layers/ipc/ShadowLayerUtils.h
@@ -6,16 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef IPC_ShadowLayerUtils_h
 #define IPC_ShadowLayerUtils_h
 
 #include "IPC/IPCMessageUtils.h"
 #include "Layers.h"
 #include "GLContext.h"
+#include "mozilla/WidgetUtils.h"
 
 #if defined(MOZ_ENABLE_D3D10_LAYER)
 # include "mozilla/layers/ShadowLayerUtilsD3D10.h"
 #endif
 
 #if defined(MOZ_X11)
 # include "mozilla/layers/ShadowLayerUtilsX11.h"
 #else
@@ -102,11 +103,18 @@ struct ParamTraits<mozilla::gl::TextureI
 template <>
 struct ParamTraits<mozilla::layers::MagicGrallocBufferHandle> {
   typedef mozilla::layers::MagicGrallocBufferHandle paramType;
   static void Write(Message*, const paramType&) {}
   static bool Read(const Message*, void**, paramType*) { return false; }
 };
 #endif  // !defined(MOZ_HAVE_XSURFACEDESCRIPTORGRALLOC)
 
-}
+template <>
+struct ParamTraits<mozilla::ScreenRotation>
+  : public EnumSerializer<mozilla::ScreenRotation,
+                          mozilla::ROTATION_0,
+                          mozilla::ROTATION_COUNT>
+{};
+
+} // namespace IPC
 
 #endif // IPC_ShadowLayerUtils_h
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -36,17 +36,22 @@ typedef std::set<ShadowableLayer*> Shado
 class Transaction
 {
 public:
   Transaction()
     : mSwapRequired(false)
     , mOpen(false)
   {}
 
-  void Begin() { mOpen = true; }
+  void Begin(const nsIntRect& aTargetBounds, ScreenRotation aRotation)
+  {
+    mOpen = true;
+    mTargetBounds = aTargetBounds;
+    mTargetRotation = aRotation;
+  }
 
   void AddEdit(const Edit& aEdit)
   {
     NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?");
     mCset.push_back(aEdit);
   }
   void AddPaint(const Edit& aPaint)
   {
@@ -87,16 +92,18 @@ public:
     return mCset.empty() && mPaints.empty() && mMutants.empty();
   }
   bool Finished() const { return !mOpen && Empty(); }
 
   EditVector mCset;
   EditVector mPaints;
   BufferArray mDyingBuffers;
   ShadowableLayerSet mMutants;
+  nsIntRect mTargetBounds;
+  ScreenRotation mTargetRotation;
   bool mSwapRequired;
 
 private:
   bool mOpen;
 
   // disabled
   Transaction(const Transaction&);
   Transaction& operator=(const Transaction&);
@@ -118,21 +125,22 @@ ShadowLayerForwarder::ShadowLayerForward
 
 ShadowLayerForwarder::~ShadowLayerForwarder()
 {
   NS_ABORT_IF_FALSE(mTxn->Finished(), "unfinished transaction?");
   delete mTxn;
 }
 
 void
-ShadowLayerForwarder::BeginTransaction()
+ShadowLayerForwarder::BeginTransaction(const nsIntRect& aTargetBounds,
+                                       ScreenRotation aRotation)
 {
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
   NS_ABORT_IF_FALSE(mTxn->Finished(), "uncommitted txn?");
-  mTxn->Begin();
+  mTxn->Begin(aTargetBounds, aRotation);
 }
 
 static PLayerChild*
 Shadow(ShadowableLayer* aLayer)
 {
   return aLayer->GetShadow();
 }
 
@@ -320,32 +328,35 @@ ShadowLayerForwarder::EndTransaction(Inf
     cset.AppendElements(&mTxn->mCset.front(), mTxn->mCset.size());
   }
   // Paints after non-paint ops, including attribute changes.  See
   // above.
   if (!mTxn->mPaints.empty()) {
     cset.AppendElements(&mTxn->mPaints.front(), mTxn->mPaints.size());
   }
 
+  TargetConfig targetConfig(mTxn->mTargetBounds, mTxn->mTargetRotation);
+
   MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
   PlatformSyncBeforeUpdate();
 
   if (mTxn->mSwapRequired) {
     MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
     RenderTraceScope rendertrace3("Forward Transaction", "000093");
-    if (!mShadowManager->SendUpdate(cset, mIsFirstPaint, aReplies)) {
+    if (!mShadowManager->SendUpdate(cset, targetConfig, mIsFirstPaint,
+                                    aReplies)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
     }
   } else {
     // If we don't require a swap we can call SendUpdateNoSwap which
     // assumes that aReplies is empty (DEBUG assertion)
     MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
     RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
-    if (!mShadowManager->SendUpdateNoSwap(cset, mIsFirstPaint)) {
+    if (!mShadowManager->SendUpdateNoSwap(cset, targetConfig, mIsFirstPaint)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
     }
   }
 
   mIsFirstPaint = false;
   MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
   return true;
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -9,16 +9,17 @@
 #define mozilla_layers_ShadowLayers_h 1
 
 #include "gfxASurface.h"
 #include "GLDefs.h"
 
 #include "ImageLayers.h"
 #include "LayersBackend.h"
 #include "mozilla/ipc/SharedMemory.h"
+#include "mozilla/WidgetUtils.h"
 
 class gfxSharedImageSurface;
 
 namespace mozilla {
 
 namespace gl {
 class GLContext;
 class TextureImage;
@@ -111,17 +112,18 @@ public:
   typedef gfxASurface::gfxContentType gfxContentType;
 
   virtual ~ShadowLayerForwarder();
 
   /**
    * Begin recording a transaction to be forwarded atomically to a
    * ShadowLayerManager.
    */
-  void BeginTransaction();
+  void BeginTransaction(const nsIntRect& aTargetBounds,
+                        ScreenRotation aRotation);
 
   /**
    * The following methods may only be called after BeginTransaction()
    * but before EndTransaction().  They mirror the LayerManager
    * interface in Layers.h.
    */
 
   /**
--- a/gfx/layers/ipc/ShadowLayersManager.h
+++ b/gfx/layers/ipc/ShadowLayersManager.h
@@ -5,22 +5,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_ShadowLayersManager_h
 #define mozilla_layers_ShadowLayersManager_h
 
 namespace mozilla {
 namespace layers {
 
+class TargetConfig;
 class ShadowLayersParent;
 
 class ShadowLayersManager
 {
 public:
     virtual void ShadowLayersUpdated(ShadowLayersParent* aLayerTree,
-                                     // FIXME nuke this
+                                     const TargetConfig& aTargetConfig,
                                      bool isFirstPaint) = 0;
 };
 
 } // layers
 } // mozilla
 
 #endif // mozilla_layers_ShadowLayersManager_h
--- a/gfx/layers/ipc/ShadowLayersParent.cpp
+++ b/gfx/layers/ipc/ShadowLayersParent.cpp
@@ -114,26 +114,28 @@ ShadowLayersParent::Destroy()
       static_cast<ShadowLayerParent*>(ManagedPLayerParent()[i]);
     slp->Destroy();
   }
 }
 
 /* virtual */
 bool
 ShadowLayersParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,
-                 const bool& isFirstPaint)
+                                     const TargetConfig& targetConfig,
+                                     const bool& isFirstPaint)
 {
   InfallibleTArray<EditReply> noReplies;
-  bool success = RecvUpdate(cset, isFirstPaint, &noReplies);
+  bool success = RecvUpdate(cset, targetConfig, isFirstPaint, &noReplies);
   NS_ABORT_IF_FALSE(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits");
   return success;
 }
 
 bool
 ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
+                               const TargetConfig& targetConfig,
                                const bool& isFirstPaint,
                                InfallibleTArray<EditReply>* reply)
 {
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp updateStart = TimeStamp::Now();
 #endif
 
   MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length()));
@@ -412,17 +414,17 @@ ShadowLayersParent::RecvUpdate(const Inf
     reply->AppendElements(&replyv.front(), replyv.size());
   }
 
   // Ensure that any pending operations involving back and front
   // buffers have completed, so that neither process stomps on the
   // other's buffer contents.
   ShadowLayerManager::PlatformSyncBeforeReplyUpdate();
 
-  mShadowLayersManager->ShadowLayersUpdated(this, isFirstPaint);
+  mShadowLayersManager->ShadowLayersUpdated(this, targetConfig, isFirstPaint);
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   int compositeTime = (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds();
   if (compositeTime > 15) {
     printf_stderr("Compositor: Layers update took %i ms (blocking gecko).\n", compositeTime);
   }
 #endif
 
--- a/gfx/layers/ipc/ShadowLayersParent.h
+++ b/gfx/layers/ipc/ShadowLayersParent.h
@@ -43,23 +43,25 @@ public:
   uint64_t GetId() const { return mId; }
   ContainerLayer* GetRoot() const { return mRoot; }
 
   virtual void DestroySharedSurface(gfxSharedImageSurface* aSurface);
   virtual void DestroySharedSurface(SurfaceDescriptor* aSurface);
 
 protected:
   virtual bool RecvUpdate(const EditArray& cset,
+                          const TargetConfig& targetConfig,
                           const bool& isFirstPaint,
                           EditReplyArray* reply) MOZ_OVERRIDE;
 
   virtual bool RecvDrawToSurface(const SurfaceDescriptor& surfaceIn,
                                  SurfaceDescriptor* surfaceOut) MOZ_OVERRIDE;
 
   virtual bool RecvUpdateNoSwap(const EditArray& cset,
+                                const TargetConfig& targetConfig,
                                 const bool& isFirstPaint) MOZ_OVERRIDE;
 
   virtual PGrallocBufferParent*
   AllocPGrallocBuffer(const gfxIntSize& aSize, const gfxContentType& aContent,
                       MaybeMagicGrallocBufferHandle* aOutHandle) MOZ_OVERRIDE;
   virtual bool
   DeallocPGrallocBuffer(PGrallocBufferParent* actor) MOZ_OVERRIDE;
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -3637,16 +3637,39 @@ gfxFontGroup::InitScriptRun(gfxContext *
             }
         }
 
         runStart += matchedLength;
     }
 }
 
 already_AddRefed<gfxFont>
+gfxFontGroup::TryOtherFamilyMembers(gfxFont* aFont, PRUint32 aCh)
+{
+    gfxFontFamily *family = aFont->GetFontEntry()->Family();
+    if (family && !aFont->GetFontEntry()->mIsProxy &&
+        family->TestCharacterMap(aCh)) {
+        // Note that we don't need the actual runScript in matchData for
+        // gfxFontFamily::SearchAllFontsForChar, it's only used for the
+        // system-fallback case. So we can just set it to 0 here.
+        GlobalFontMatch matchData(aCh, 0, &mStyle);
+        family->SearchAllFontsForChar(&matchData);
+        gfxFontEntry *fe = matchData.mBestMatch;
+        if (fe) {
+            bool needsBold = aFont->GetStyle()->weight >= 600 && !fe->IsBold();
+            nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, needsBold);
+            if (font) {
+                return font.forget();
+            }
+        }
+    }
+    return nsnull;
+}
+
+already_AddRefed<gfxFont>
 gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
                               PRInt32 aRunScript, gfxFont *aPrevMatchedFont,
                               PRUint8 *aMatchType)
 {
     // To optimize common cases, try the first font in the font-group
     // before going into the more detailed checks below
     PRUint32 nextIndex = 0;
     bool isJoinControl = gfxFontUtils::IsJoinControl(aCh);
@@ -3655,16 +3678,23 @@ gfxFontGroup::FindFontForChar(PRUint32 a
 
     if (!isJoinControl && !wasJoinCauser && !isVarSelector) {
         gfxFont *firstFont = mFonts[0];
         if (firstFont->HasCharacter(aCh)) {
             *aMatchType = gfxTextRange::kFontGroup;
             firstFont->AddRef();
             return firstFont;
         }
+        // It's possible that another font in the family (e.g. regular face,
+        // where the requested style was italic) will support the character
+        nsRefPtr<gfxFont> font = TryOtherFamilyMembers(firstFont, aCh);
+        if (font) {
+            *aMatchType = gfxTextRange::kFontGroup;
+            return font.forget();
+        }
         // we don't need to check the first font again below
         ++nextIndex;
     }
 
     if (aPrevMatchedFont) {
         // Don't switch fonts for control characters, regardless of
         // whether they are present in the current font, as they won't
         // actually be rendered (see bug 716229)
@@ -3700,32 +3730,20 @@ gfxFontGroup::FindFontForChar(PRUint32 a
     PRUint32 fontListLength = FontListLength();
     for (PRUint32 i = nextIndex; i < fontListLength; i++) {
         nsRefPtr<gfxFont> font = mFonts[i];
         if (font->HasCharacter(aCh)) {
             *aMatchType = gfxTextRange::kFontGroup;
             return font.forget();
         }
 
-        // check other faces of the family
-        gfxFontFamily *family = font->GetFontEntry()->Family();
-        if (family && !font->GetFontEntry()->mIsProxy &&
-            family->TestCharacterMap(aCh))
-        {
-            GlobalFontMatch matchData(aCh, aRunScript, &mStyle);
-            family->SearchAllFontsForChar(&matchData);
-            gfxFontEntry *fe = matchData.mBestMatch;
-            if (fe) {
-                bool needsBold =
-                    font->GetStyle()->weight >= 600 && !fe->IsBold();
-                font = fe->FindOrMakeFont(font->GetStyle(), needsBold);
-                if (font) {
-                    return font.forget();
-                }
-            }
+        font = TryOtherFamilyMembers(font, aCh);
+        if (font) {
+            *aMatchType = gfxTextRange::kFontGroup;
+            return font.forget();
         }
     }
 
     // if character is in Private Use Area, don't do matching against pref or system fonts
     if ((aCh >= 0xE000  && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
         return nsnull;
 
     // 2. search pref fonts
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -3176,16 +3176,22 @@ protected:
     bool ForEachFontInternal(const nsAString& aFamilies,
                                nsIAtom *aLanguage,
                                bool aResolveGeneric,
                                bool aResolveFontName,
                                bool aUseFontSet,
                                FontCreationCallback fc,
                                void *closure);
 
+    // Helper for font-matching:
+    // see if aCh is supported in any of the other faces from aFont's family;
+    // if so return the best style match, else return null.
+    already_AddRefed<gfxFont> TryOtherFamilyMembers(gfxFont* aFont,
+                                                    PRUint32 aCh);
+
     static bool FontResolverProc(const nsAString& aName, void *aClosure);
 
     static bool FindPlatformFont(const nsAString& aName,
                                    const nsACString& aGenericName,
                                    bool aUseFontSet,
                                    void *closure);
 
     static NS_HIDDEN_(nsILanguageAtomService*) gLangService;
--- a/intl/uconv/idl/nsIUTF8ConverterService.idl
+++ b/intl/uconv/idl/nsIUTF8ConverterService.idl
@@ -21,26 +21,28 @@ interface nsIUTF8ConverterService : nsIS
    *        'UTF8ness' check. Set this to PR_TRUE only if you suspect that 
    *        aString can be mistaken for ASCII / UTF-8 but is actually NOT 
    *        in ASCII / UTF-8 so that aString has to go through the conversion.
    *        skipping ASCIIness/UTF8ness check.
    *        The most common case is the input is in 7bit non-ASCII charsets
    *        like ISO-2022-JP, HZ or UTF-7 (in its original form or
    *        a modified form used in IMAP folder names).
    * @param aAllowSubstitution when true, allow the decoder to substitute
-   *        invalid input sequences by replacement characters
+   *        invalid input sequences by replacement characters (defaults to
+   *        true)
    * @return the converted string in UTF-8.
    * @throws NS_ERROR_UCONV_NOCONV when there is no decoder for aCharset
    *         or error code of nsIUnicodeDecoder in case of conversion failure
    */
 
+    [optional_argc]
     AUTF8String convertStringToUTF8(in ACString aString, 
                                     in string   aCharset,
                                     in boolean  aSkipCheck,
-                                    in boolean  aAllowSubstitution);
+                                    [optional] in boolean aAllowSubstitution);
 
 /* XXX : To-be-added. convertStringFromUTF8 */
    
   /**
    * Ensure that |aSpec| (after URL-unescaping it) is encoded in UTF-8.  
    * If not,  convert it to UTF-8, assuming it's encoded in |aCharset|,  
    * and return the result.
    *
--- a/intl/uconv/src/nsUTF8ConverterService.cpp
+++ b/intl/uconv/src/nsUTF8ConverterService.cpp
@@ -54,30 +54,33 @@ ToUTF8(const nsACString &aString, const 
   return rv;
 }
 
 NS_IMETHODIMP  
 nsUTF8ConverterService::ConvertStringToUTF8(const nsACString &aString, 
                                             const char *aCharset, 
                                             bool aSkipCheck, 
                                             bool aAllowSubstitution,
+                                            PRUint8 aOptionalArgc,
                                             nsACString &aUTF8String)
 {
+  bool allowSubstitution = (aOptionalArgc == 1) ? aAllowSubstitution : true;
+
   // return if ASCII only or valid UTF-8 providing that the ASCII/UTF-8
   // check is requested. It may not be asked for if a caller suspects
   // that the input is in non-ASCII 7bit charset (ISO-2022-xx, HZ) or 
   // it's in a charset other than UTF-8 that can be mistaken for UTF-8.
   if (!aSkipCheck && (IsASCII(aString) || IsUTF8(aString))) {
     aUTF8String = aString;
     return NS_OK;
   }
 
   aUTF8String.Truncate();
 
-  nsresult rv = ToUTF8(aString, aCharset, aAllowSubstitution, aUTF8String);
+  nsresult rv = ToUTF8(aString, aCharset, allowSubstitution, aUTF8String);
 
   // additional protection for cases where check is skipped and  the input
   // is actually in UTF-8 as opposed to aCharset. (i.e. caller's hunch
   // was wrong.) We don't check ASCIIness assuming there's no charset
   // incompatible with ASCII (we don't support EBCDIC).
   if (aSkipCheck && NS_FAILED(rv) && IsUTF8(aString)) {
     aUTF8String = aString;
     return NS_OK;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -80,16 +80,96 @@ GetBuildConfiguration(JSContext *cx, uns
 #ifdef JS_THREADSAFE
     value = BooleanValue(true);
 #else
     value = BooleanValue(false);
 #endif
     if (!JS_SetProperty(cx, info, "has-gczeal", &value))
         return false;
 
+#ifdef JS_MORE_DETERMINISTIC
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "more-deterministic", &value))
+        return false;
+
+#ifdef MOZ_PROFILING
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "profiling", &value))
+        return false;
+
+#ifdef INCLUDE_MOZILLA_DTRACE
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "dtrace", &value))
+        return false;
+
+#ifdef MOZ_TRACE_JSCALLS
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "trace-jscalls-api", &value))
+        return false;
+
+#ifdef JSGC_INCREMENTAL
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "incremental-gc", &value))
+        return false;
+
+#ifdef JSGC_GENERATIONAL
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "generational-gc", &value))
+        return false;
+
+#ifdef MOZ_VALGRIND
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "valgrind", &value))
+        return false;
+
+#ifdef JS_OOM_DO_BACKTRACES
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "oom-backtraces", &value))
+        return false;
+
+#ifdef JS_METHODJIT
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "methodjit", &value))
+        return false;
+
+#ifdef JS_HAS_XML_SUPPORT
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "e4x", &value))
+        return false;
+
     *vp = ObjectValue(*info);
     return true;
 }
 
 static JSBool
 GC(JSContext *cx, unsigned argc, jsval *vp)
 {
     /*
@@ -378,17 +458,17 @@ GCPreserveCode(JSContext *cx, unsigned a
 static JSBool
 DeterministicGC(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (argc != 1) {
         ReportUsageError(cx, &JS_CALLEE(cx, vp).toObject(), "Wrong number of arguments");
         return JS_FALSE;
     }
 
-    gc::SetDeterministicGC(cx, js_ValueToBoolean(vp[2]));
+    gc::SetDeterministicGC(cx, ToBoolean(vp[2]));
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 #endif /* JS_GC_ZEAL */
 
 struct JSCountHeapNode {
     void                *thing;
     JSGCTraceKind       kind;
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -286,21 +286,19 @@ HOST_CMMOBJS = $(addprefix host_,$(HOST_
 ifndef HOST_OBJS
 _HOST_OBJS = $(HOST_COBJS) $(HOST_CCOBJS) $(HOST_CPPOBJS) $(HOST_CMOBJS) $(HOST_CMMOBJS)
 HOST_OBJS = $(strip $(_HOST_OBJS))
 endif
 
 ifndef MOZ_AUTO_DEPS
 ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
 MDDEPFILES		= $(addprefix $(MDDEPDIR)/,$(OBJS:=.pp))
-ifndef NO_GEN_XPT
 MDDEPFILES		+= $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.h.pp) $(XPIDLSRCS:.idl=.xpt.pp))
 endif
 endif
-endif
 
 ALL_TRASH = \
 	$(GARBAGE) $(TARGETS) $(OBJS) $(PROGOBJS) LOGS TAGS a.out \
 	$(filter-out $(ASFILES),$(OBJS:.$(OBJ_SUFFIX)=.s)) $(OBJS:.$(OBJ_SUFFIX)=.ii) \
 	$(OBJS:.$(OBJ_SUFFIX)=.i) $(OBJS:.$(OBJ_SUFFIX)=.i_o) \
 	$(HOST_PROGOBJS) $(HOST_OBJS) $(IMPORT_LIBRARY) $(DEF_FILE)\
 	$(EXE_DEF_FILE) so_locations _gen _stubs $(wildcard *.res) $(wildcard *.RES) \
 	$(wildcard *.pdb) $(CODFILE) $(MAPFILE) $(IMPORT_LIBRARY) \
@@ -1293,17 +1291,16 @@ xpidl-preqs = \
 $(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) \
 	  $(PLY_INCLUDE) \
 	  $(LIBXUL_DIST)/sdk/bin/header.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
 	@if test -n "$(findstring $*.h, $(EXPORTS))"; \
 	  then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi
 
-ifndef NO_GEN_XPT
 # generate intermediate .xpt files into $(XPIDL_GEN_DIR), then link
 # into $(XPIDL_MODULE).xpt and export it to $(FINAL_TARGET)/components.
 $(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) \
 	  $(PLY_INCLUDE) \
 	  -I$(topsrcdir)/xpcom/typelib/xpt/tools \
 	  $(LIBXUL_DIST)/sdk/bin/typelib.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
@@ -1318,18 +1315,16 @@ libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).
 ifndef NO_DIST_INSTALL
 	$(call install_cmd,$(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components)
 ifndef NO_INTERFACES_MANIFEST
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
 endif
 endif
 
-endif # NO_GEN_XPT
-
 GARBAGE_DIRS		+= $(XPIDL_GEN_DIR)
 
 endif #} XPIDLSRCS
 
 
 ifndef INCLUDED_XPIDL_MK
   include $(topsrcdir)/config/makefiles/xpidl.mk
 endif
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -594,16 +594,18 @@ EmitNonLocalJumpFixup(JSContext *cx, Byt
                  * For a for-let-in statement, pushing/popping the block is
                  * interleaved with JSOP_(END)ITER. Just handle both together
                  * here and skip over the enclosing STMT_FOR_IN_LOOP.
                  */
                 JS_ASSERT(stmt->down->type == STMT_FOR_IN_LOOP);
                 stmt = stmt->down;
                 if (stmt == toStmt)
                     break;
+                if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
+                    return false;
                 if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
                     return false;
                 if (!PopIterator(cx, bce))
                     return false;
                 if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
                     return false;
                 EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
             } else {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/function-tosource-genexpr.js
@@ -0,0 +1,7 @@
+function getgen() {
+    gen = getgen.caller;
+}
+var gen;
+(getgen() for (x of [1])).next();
+assertEq(gen.toSource(), "function genexp() {\n    [generator expression]\n}");
+assertEq(decompileBody(gen), "\n    [generator expression]\n");
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -317,17 +317,17 @@ JS_ConvertArgumentsVA(JSContext *cx, uns
                     }
                 }
                 return JS_FALSE;
             }
             break;
         }
         switch (c) {
           case 'b':
-            *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp);
+            *va_arg(ap, JSBool *) = ToBoolean(*sp);
             break;
           case 'c':
             if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16_t *)))
                 return JS_FALSE;
             break;
           case 'i':
             if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32_t *)))
                 return JS_FALSE;
@@ -475,17 +475,17 @@ JS_ConvertValue(JSContext *cx, jsval v, 
             *vp = STRING_TO_JSVAL(str);
         break;
       case JSTYPE_NUMBER:
         ok = JS_ValueToNumber(cx, v, &d);
         if (ok)
             *vp = DOUBLE_TO_JSVAL(d);
         break;
       case JSTYPE_BOOLEAN:
-        *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v));
+        *vp = BooleanValue(ToBoolean(v));
         return JS_TRUE;
       default: {
         char numBuf[12];
         JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
         ok = JS_FALSE;
         break;
       }
@@ -627,17 +627,17 @@ JS_ValueToUint16(JSContext *cx, jsval v,
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
-    *bp = js_ValueToBoolean(v);
+    *bp = ToBoolean(v);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSType)
 JS_TypeOfValue(JSContext *cx, jsval v)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
@@ -5337,39 +5337,42 @@ JS_CompileFunction(JSContext *cx, JSObje
 
 JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned indent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    if (script->function())
-        return JS_DecompileFunction(cx, script->function(), indent);
+    RootedFunction fun(cx, script->function());
+    if (fun)
+        return JS_DecompileFunction(cx, fun, indent);
     return script->sourceData(cx);
 }
 
 JS_PUBLIC_API(JSString *)
-JS_DecompileFunction(JSContext *cx, JSFunction *fun, unsigned indent)
+JS_DecompileFunction(JSContext *cx, JSFunction *funArg, unsigned indent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, fun);
-    return fun->toString(cx, false, !(indent & JS_DONT_PRETTY_PRINT));
+    assertSameCompartment(cx, funArg);
+    RootedFunction fun(cx, funArg);
+    return FunctionToString(cx, fun, false, !(indent & JS_DONT_PRETTY_PRINT));
 }
 
 JS_PUBLIC_API(JSString *)
-JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, unsigned indent)
+JS_DecompileFunctionBody(JSContext *cx, JSFunction *funArg, unsigned indent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, fun);
-    return fun->toString(cx, true, !(indent & JS_DONT_PRETTY_PRINT));
+    assertSameCompartment(cx, funArg);
+    RootedFunction fun(cx, funArg);
+    return FunctionToString(cx, fun, true, !(indent & JS_DONT_PRETTY_PRINT));
 }
 
 JS_NEVER_INLINE JS_PUBLIC_API(JSBool)
 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *scriptArg_, jsval *rval)
 {
     RootedScript scriptArg(cx, scriptArg_);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2659,16 +2659,22 @@ JS_ValueToNumber(JSContext *cx, jsval v,
 
 #ifdef __cplusplus
 namespace js {
 /*
  * DO NOT CALL THIS.  Use JS::ToNumber
  */
 extern JS_PUBLIC_API(bool)
 ToNumberSlow(JSContext *cx, JS::Value v, double *dp);
+
+/*
+ * DO NOT CALL THIS. Use JS::ToBoolean
+ */
+extern JS_PUBLIC_API(bool)
+ToBooleanSlow(const JS::Value &v);
 } /* namespace js */
 
 namespace JS {
 
 /* ES5 9.3 ToNumber. */
 JS_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, const Value &v, double *out)
 {
@@ -2677,16 +2683,36 @@ ToNumber(JSContext *cx, const Value &v, 
     if (v.isNumber()) {
         *out = v.toNumber();
         MaybeCheckStackRoots(cx);
         return true;
     }
     return js::ToNumberSlow(cx, v, out);
 }
 
+JS_ALWAYS_INLINE bool
+ToBoolean(const Value &v)
+{
+    if (v.isBoolean())
+        return v.toBoolean();
+    if (v.isInt32())
+        return v.toInt32() != 0;
+    if (v.isObject())
+        return true;
+    if (v.isNullOrUndefined())
+        return false;
+    if (v.isDouble()) {
+        double d = v.toDouble();
+        return !MOZ_DOUBLE_IS_NaN(d) && d != 0;
+    }
+
+    /* Slow path. Handle Strings. */
+    return js::ToBooleanSlow(v);
+}
+
 } /* namespace JS */
 #endif /* __cplusplus */
 
 extern JS_PUBLIC_API(JSBool)
 JS_DoubleIsInt32(double d, int32_t *ip);
 
 extern JS_PUBLIC_API(int32_t)
 JS_DoubleToInt32(double d);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3086,31 +3086,31 @@ class ArrayForEachBehavior
     static Value lateExitValue() { return UndefinedValue(); }
 };
 
 class ArrayEveryBehavior
 {
   public:
     static bool shouldExit(Value &callval, Value *rval)
     {
-        if (!js_ValueToBoolean(callval)) {
+        if (!ToBoolean(callval)) {
             *rval = BooleanValue(false);
             return true;
         }
         return false;
     }
     static Value lateExitValue() { return BooleanValue(true); }
 };
 
 class ArraySomeBehavior
 {
   public:
     static bool shouldExit(Value &callval, Value *rval)
     {
-        if (js_ValueToBoolean(callval)) {
+        if (ToBoolean(callval)) {
             *rval = BooleanValue(true);
             return true;
         }
         return false;
     }
     static Value lateExitValue() { return BooleanValue(false); }
 };
 
@@ -3342,17 +3342,17 @@ array_filter(JSContext *cx, unsigned arg
             ag.setCallee(ObjectValue(*callable));
             ag.thisv() = thisv;
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
 
-            if (js_ValueToBoolean(ag.rval())) {
+            if (ToBoolean(ag.rval())) {
                 if(!SetArrayElement(cx, arr, to, kValue))
                     return false;
                 to++;
             }
         }
 
         /* Step d. */
         k++;
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -124,17 +124,17 @@ static JSFunctionSpec boolean_methods[] 
     JS_FS_END
 };
 
 static JSBool
 Boolean(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    bool b = args.length() != 0 ? js_ValueToBoolean(args[0]) : false;
+    bool b = args.length() != 0 ? JS::ToBoolean(args[0]) : false;
 
     if (IsConstructing(vp)) {
         JSObject *obj = BooleanObject::create(cx, b);
         if (!obj)
             return false;
         args.rval().setObject(*obj);
     } else {
         args.rval().setBoolean(b);
@@ -186,44 +186,32 @@ js_InitBooleanClass(JSContext *cx, JSObj
 JSString *
 js_BooleanToString(JSContext *cx, JSBool b)
 {
     return cx->runtime->atomState.booleanAtoms[b ? 1 : 0];
 }
 
 namespace js {
 
+JS_PUBLIC_API(bool)
+ToBooleanSlow(const Value &v)
+{
+    JS_ASSERT(v.isString());
+    return v.toString()->length() != 0;
+}
+
 bool
 BooleanGetPrimitiveValueSlow(JSContext *cx, JSObject &obj, Value *vp)
 {
     InvokeArgsGuard ag;
     if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
     ag.calleev() = cx->compartment->maybeGlobal()->booleanValueOf();
     ag.thisv().setObject(obj);
     if (!Invoke(cx, ag))
         return false;
     *vp = ag.rval();
     return true;
 }
 
 }  /* namespace js */
 
-JSBool
-js_ValueToBoolean(const Value &v)
-{
-    if (v.isInt32())
-        return v.toInt32() != 0;
-    if (v.isString())
-        return v.toString()->length() != 0;
-    if (v.isObject())
-        return JS_TRUE;
-    if (v.isNullOrUndefined())
-        return JS_FALSE;
-    if (v.isDouble()) {
-        double d;
 
-        d = v.toDouble();
-        return !MOZ_DOUBLE_IS_NaN(d) && d != 0;
-    }
-    JS_ASSERT(v.isBoolean());
-    return v.toBoolean();
-}
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -21,12 +21,9 @@ js_BooleanToString(JSContext *cx, JSBool
 
 namespace js {
 
 inline bool
 BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp);
 
 } /* namespace js */
 
-extern JSBool
-js_ValueToBoolean(const js::Value &v);
-
 #endif /* jsbool_h___ */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -521,17 +521,17 @@ JS_FRIEND_DATA(Class) js::FunctionClass 
     fun_hasInstance,
     NULL,                    /* construct   */
     fun_trace
 };
 
 
 /* Find the body of a function (not including braces). */
 static bool
-FindBody(JSContext *cx, JSFunction *fun, const jschar *chars, size_t length,
+FindBody(JSContext *cx, HandleFunction fun, const jschar *chars, size_t length,
          size_t *bodyStart, size_t *bodyEnd)
 {
     // We don't need principals, since those are only used for error reporting.
     TokenStream ts(cx, NULL, NULL, chars, length, "internal-FindBody", 0,
                    fun->script()->getVersion(), NULL);
     JS_ASSERT(chars[0] == '(');
     int nest = 0;
     bool onward = true;
@@ -568,93 +568,102 @@ FindBody(JSContext *cx, JSFunction *fun,
     } else {
         JS_ASSERT(!braced);
     }
     *bodyEnd = p.get() - chars;
     return true;
 }
 
 JSString *
-JSFunction::toString(JSContext *cx, bool bodyOnly, bool lambdaParen)
+js::FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen)
 {
     StringBuffer out(cx);
 
+    if (fun->isInterpreted() && fun->script()->isGeneratorExp) {
+        if ((!bodyOnly && !out.append("function genexp() {")) ||
+            !out.append("\n    [generator expression]\n") ||
+            (!bodyOnly && !out.append("}"))) {
+            return NULL;
+        }
+        return out.finishString();
+    }
     if (!bodyOnly) {
         // If we're not in pretty mode, put parentheses around lambda functions.
-        if (isInterpreted() && !lambdaParen && (flags & JSFUN_LAMBDA)) {
+        if (fun->isInterpreted() && !lambdaParen && (fun->flags & JSFUN_LAMBDA)) {
             if (!out.append("("))
                 return NULL;
         }
         if (!out.append("function "))
             return NULL;
-        if (atom) {
-            if (!out.append(atom))
+        if (fun->atom) {
+            if (!out.append(fun->atom))
                 return NULL;
         }
     }
-    bool haveSource = isInterpreted();
-    if (haveSource && !script()->source && !script()->loadSource(cx, &haveSource))
+    bool haveSource = fun->isInterpreted();
+    if (haveSource && !fun->script()->source && !fun->script()->loadSource(cx, &haveSource))
             return NULL;
     if (haveSource) {
-        RootedString src(cx, script()->sourceData(cx));
+        RootedScript script(cx, fun->script());
+        RootedString src(cx, fun->script()->sourceData(cx));
         if (!src)
             return NULL;
         const jschar *chars = src->getChars(cx);
         if (!chars)
             return NULL;
-        bool exprBody = flags & JSFUN_EXPR_CLOSURE;
+        bool exprBody = fun->flags & JSFUN_EXPR_CLOSURE;
 
         // The source data for functions created by calling the Function
         // constructor is only the function's body.
-        bool funCon = script()->sourceStart == 0 && script()->source->argumentsNotIncluded();
+        bool funCon = script->sourceStart == 0 && script->source->argumentsNotIncluded();
 
         // Functions created with the constructor should not be using the
         // expression body extension.
         JS_ASSERT_IF(funCon, !exprBody);
         JS_ASSERT_IF(!funCon, src->length() > 0 && chars[0] == '(');
 
         // If a function inherits strict mode by having scopes above it that
         // have "use strict", we insert "use strict" into the body of the
         // function. This ensures that if the result of toString is evaled, the
         // resulting function will have the same semantics.
-        bool addUseStrict = script()->strictModeCode && !script()->explicitUseStrict;
+        bool addUseStrict = script->strictModeCode && !script->explicitUseStrict;
 
         // Functions created with the constructor can't have inherited strict
         // mode.
         JS_ASSERT(!funCon || !addUseStrict);
         bool buildBody = funCon && !bodyOnly;
         if (buildBody) {
             // This function was created with the Function constructor. We don't
             // have source for the arguments, so we have to generate that. Part
             // of bug 755821 should be cobbling the arguments passed into the
             // Function constructor into the source string.
             if (!out.append("("))
                 return NULL;
 
             // Fish out the argument names.
             BindingVector *localNames = cx->new_<BindingVector>(cx);
             js::ScopedDeletePtr<BindingVector> freeNames(localNames);
-            if (!GetOrderedBindings(cx, script()->bindings, localNames))
+            if (!GetOrderedBindings(cx, script->bindings, localNames))
                 return NULL;
-            for (unsigned i = 0; i < nargs; i++) {
+            for (unsigned i = 0; i < fun->nargs; i++) {
                 if ((i && !out.append(", ")) ||
-                    (i == unsigned(nargs - 1) && hasRest() && !out.append("...")) ||
+                    (i == unsigned(fun->nargs - 1) && fun->hasRest() && !out.append("...")) ||
                     !out.append((*localNames)[i].maybeName)) {
                     return NULL;
                 }
             }
             if (!out.append(") {\n"))
                 return NULL;
         }
         if ((bodyOnly && !funCon) || addUseStrict) {
             // We need to get at the body either because we're only supposed to
             // return the body or we need to insert "use strict" into the body.
             JS_ASSERT(!buildBody);
             size_t bodyStart = 0, bodyEnd = 0;
-            if (!FindBody(cx, this, chars, src->length(), &bodyStart, &bodyEnd))
+            if (!FindBody(cx, fun, chars, src->length(), &bodyStart, &bodyEnd))
                 return NULL;
 
             if (addUseStrict) {
                 // Output source up to beginning of body.
                 if (!out.append(chars, bodyStart))
                     return NULL;
                 if (exprBody) {
                     // We can't insert a statement into a function with an
@@ -680,29 +689,29 @@ JSFunction::toString(JSContext *cx, bool
         if (buildBody) {
             if (!out.append("\n}"))
                 return NULL;
         }
         if (bodyOnly) {
             // Slap a semicolon on the end of functions with an expression body.
             if (exprBody && !out.append(";"))
                 return NULL;
-        } else if (!lambdaParen && (flags & JSFUN_LAMBDA)) {
+        } else if (!lambdaParen && (fun->flags & JSFUN_LAMBDA)) {
             if (!out.append(")"))
                 return NULL;
         }
-    } else if (isInterpreted()) {
+    } else if (fun->isInterpreted()) {
         if ((!bodyOnly && !out.append("() {\n    ")) ||
             !out.append("[sourceless code]") ||
             (!bodyOnly && !out.append("\n}")))
             return NULL;
-        if (!lambdaParen && (flags & JSFUN_LAMBDA) && (!out.append(")")))
+        if (!lambdaParen && (fun->flags & JSFUN_LAMBDA) && (!out.append(")")))
             return NULL;
     } else {
-        JS_ASSERT(!(flags & JSFUN_EXPR_CLOSURE));
+        JS_ASSERT(!(fun->flags & JSFUN_EXPR_CLOSURE));
         if ((!bodyOnly && !out.append("() {\n    ")) ||
             !out.append("[native code]") ||
             (!bodyOnly && !out.append("\n}")))
             return NULL;
     }
     return out.finishString();
 }
 
@@ -714,21 +723,18 @@ fun_toStringHelper(JSContext *cx, JSObje
             return Proxy::fun_toString(cx, obj, indent);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_PROTO,
                              js_Function_str, js_toString_str,
                              "object");
         return NULL;
     }
 
-    JSFunction *fun = obj->toFunction();
-    if (!fun)
-        return NULL;
-
-    return fun->toString(cx, false, indent != JS_DONT_PRETTY_PRINT);
+    RootedFunction fun(cx, obj->toFunction());
+    return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT);
 }
 
 static JSBool
 fun_toString(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_ASSERT(IsFunctionObject(vp[0]));
     uint32_t indent = 0;
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -148,18 +148,16 @@ struct JSFunction : public JSObject
     inline bool initBoundFunction(JSContext *cx, js::HandleValue thisArg,
                                   const js::Value *args, unsigned argslen);
 
     inline JSObject *getBoundFunctionTarget() const;
     inline const js::Value &getBoundFunctionThis() const;
     inline const js::Value &getBoundFunctionArgument(unsigned which) const;
     inline size_t getBoundFunctionArgumentCount() const;
 
-    JSString *toString(JSContext *cx, bool bodyOnly, bool pretty);
-
   private:
     inline js::FunctionExtended *toExtended();
     inline const js::FunctionExtended *toExtended() const;
 
     inline bool isExtended() const {
         JS_STATIC_ASSERT(FinalizeKind != ExtendedFinalizeKind);
         JS_ASSERT(!!(flags & JSFUN_EXTENDED) == (getAllocKind() == ExtendedFinalizeKind));
         return !!(flags & JSFUN_EXTENDED);
@@ -243,16 +241,18 @@ inline const js::FunctionExtended *
 JSFunction::toExtended() const
 {
     JS_ASSERT(isExtended());
     return static_cast<const js::FunctionExtended *>(this);
 }
 
 namespace js {
 
+JSString *FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen);
+
 template<XDRMode mode>
 bool
 XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope,
                        HandleScript enclosingScript, JSObject **objp);
 
 extern JSObject *
 CloneInterpretedFunction(JSContext *cx, HandleObject enclosingScope, HandleFunction fun);
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -880,20 +880,18 @@ DoIncDec(JSContext *cx, HandleScript scr
 #define POP_COPY_TO(v)           v = *--regs.sp
 #define POP_RETURN_VALUE()       regs.fp()->setReturnValue(*--regs.sp)
 
 #define VALUE_TO_BOOLEAN(cx, vp, b)                                           \
     JS_BEGIN_MACRO                                                            \
         vp = &regs.sp[-1];                                                    \
         if (vp->isNull()) {                                                   \
             b = false;                                                        \
-        } else if (vp->isBoolean()) {                                         \
-            b = vp->toBoolean();                                              \
         } else {                                                              \
-            b = !!js_ValueToBoolean(*vp);                                     \
+            b = ToBoolean(*vp);                                               \
         }                                                                     \
     JS_END_MACRO
 
 #define POP_BOOLEAN(cx, vp, b)   do { VALUE_TO_BOOLEAN(cx, vp, b); regs.sp--; } while(0)
 
 #define FETCH_OBJECT(cx, n, obj)                                              \
     JS_BEGIN_MACRO                                                            \
         Value *vp_ = &regs.sp[n];                                             \
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -730,17 +730,17 @@ Iterator(JSContext *cx, unsigned argc, V
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
 
     bool keyonly = false;
     if (args.length() >= 2)
-        keyonly = js_ValueToBoolean(args[1]);
+        keyonly = ToBoolean(args[1]);
     unsigned flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE));
 
     if (!ValueToIterator(cx, flags, &args[0]))
         return false;
     args.rval() = args[0];
     return true;
 }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1296,27 +1296,27 @@ PropDesc::initialize(JSContext *cx, cons
     RootedId id(cx);
 
     /* 8.10.5 step 3 */
     id = NameToId(cx->runtime->atomState.enumerableAtom);
     if (!HasProperty(cx, desc, id, &v, &found))
         return false;
     if (found) {
         hasEnumerable_ = true;
-        if (js_ValueToBoolean(v))
+        if (ToBoolean(v))
             attrs |= JSPROP_ENUMERATE;
     }
 
     /* 8.10.5 step 4 */
     id = NameToId(cx->runtime->atomState.configurableAtom);
     if (!HasProperty(cx, desc, id, &v, &found))
         return false;
     if (found) {
         hasConfigurable_ = true;
-        if (js_ValueToBoolean(v))
+        if (ToBoolean(v))
             attrs &= ~JSPROP_PERMANENT;
     }
 
     /* 8.10.5 step 5 */
     id = NameToId(cx->runtime->atomState.valueAtom);
     if (!HasProperty(cx, desc, id, &v, &found))
         return false;
     if (found) {
@@ -1325,17 +1325,17 @@ PropDesc::initialize(JSContext *cx, cons
     }
 
     /* 8.10.6 step 6 */
     id = NameToId(cx->runtime->atomState.writableAtom);
     if (!HasProperty(cx, desc, id, &v, &found))
         return false;
     if (found) {
         hasWritable_ = true;
-        if (js_ValueToBoolean(v))
+        if (ToBoolean(v))
             attrs &= ~JSPROP_READONLY;
     }
 
     /* 8.10.7 step 7 */
     id = NameToId(cx->runtime->atomState.getAtom);
     if (!HasProperty(cx, desc, id, &v, &found))
         return false;
     if (found) {
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -492,16 +492,18 @@ FlowsIntoNext(JSOp op)
  * coherent fashion.
  */
 class PCCounts
 {
     friend struct ::JSScript;
     double *counts;
 #ifdef DEBUG
     size_t capacity;
+#elif JS_BITS_PER_WORD == 32
+    void *padding;
 #endif
 
  public:
 
     enum BaseCounts {
         BASE_INTERP = 0,
         BASE_METHODJIT,
 
@@ -610,16 +612,19 @@ class PCCounts
     }
 
     /* Boolean conversion, for 'if (counters) ...' */
     operator void*() const {
         return counts;
     }
 };
 
+/* Necessary for alignment with the script. */
+JS_STATIC_ASSERT(sizeof(PCCounts) % sizeof(Value) == 0);
+
 } /* namespace js */
 
 #if defined(DEBUG)
 /*
  * Disassemblers, for debugging only.
  */
 extern JS_FRIEND_API(JSBool)
 js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, js::Sprinter *sp);
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -687,17 +687,17 @@ IndicatePropertyNotFound(JSContext *cx, 
 {
     desc->obj = NULL;
     return true;
 }
 
 static bool
 ValueToBool(JSContext *cx, const Value &v, bool *bp)
 {
-    *bp = !!js_ValueToBoolean(v);
+    *bp = ToBoolean(v);
     return true;
 }
 
 static bool
 ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
 {
     JS_ASSERT(props.length() == 0);
 
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -3192,17 +3192,17 @@ reflect_parse(JSContext *cx, uint32_t ar
 
         Value prop;
 
         /* config.loc */
         RootedId locId(cx, NameToId(cx->runtime->atomState.locAtom));
         if (!baseops::GetPropertyDefault(cx, config, locId, BooleanValue(true), &prop))
             return JS_FALSE;
 
-        loc = js_ValueToBoolean(prop);
+        loc = ToBoolean(prop);
 
         if (loc) {
             /* config.source */
             RootedId sourceId(cx, NameToId(cx->runtime->atomState.sourceAtom));
             if (!baseops::GetPropertyDefault(cx, config, sourceId, NullValue(), &prop))
                 return JS_FALSE;
 
             if (!prop.isNullOrUndefined()) {
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -352,16 +352,17 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         StrictModeCode,
         ContainsDynamicNameAccess,
         FunHasExtensibleScope,
         ArgumentsHasVarBinding,
         NeedsArgsObj,
         OwnFilename,
         ParentFilename,
         IsGenerator,
+        IsGeneratorExp,
         HaveSource,
         OwnSource,
         ExplicitUseStrict
     };
 
     uint32_t length, lineno, nslots;
     uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, nClosedArgs, nClosedVars, i;
     uint32_t prologLength, version;
@@ -520,16 +521,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         }
         if (script->source) {
             scriptBits |= (1 << HaveSource);
             if (!enclosingScript || enclosingScript->source != script->source)
                 scriptBits |= (1 << OwnSource);
         }
         if (script->isGenerator)
             scriptBits |= (1 << IsGenerator);
+        if (script->isGeneratorExp)
+            scriptBits |= (1 << IsGeneratorExp);
 
         JS_ASSERT(!script->compileAndGo);
         JS_ASSERT(!script->hasSingletons);
     }
 
     if (!xdr->codeUint32(&prologLength))
         return JS_FALSE;
     if (!xdr->codeUint32(&version))
@@ -601,16 +604,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         if (scriptBits & (1 << FunHasExtensibleScope))
             script->funHasExtensibleScope = true;
         if (scriptBits & (1 << ArgumentsHasVarBinding))
             script->setArgumentsHasVarBinding();
         if (scriptBits & (1 << NeedsArgsObj))
             script->setNeedsArgsObj(true);
         if (scriptBits & (1 << IsGenerator))
             script->isGenerator = true;
+        if (scriptBits & (1 << IsGeneratorExp))
+            script->isGeneratorExp = true;
     }
 
     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
     if (!xdr->codeBytes(script->code, length) ||
         !xdr->codeBytes(notes, nsrcnotes) ||
         !xdr->codeUint32(&lineno) ||
         !xdr->codeUint32(&nslots)) {
@@ -843,16 +848,17 @@ JSScript::initScriptCounts(JSContext *cx
 
     DebugOnly<char *> base = cursor;
 
     ScriptCounts scriptCounts;
     scriptCounts.pcCountsVector = (PCCounts *) cursor;
     cursor += length * sizeof(PCCounts);
 
     for (pc = code; pc < code + length; pc = next) {
+        JS_ASSERT(uintptr_t(cursor) % sizeof(double) == 0);
         scriptCounts.pcCountsVector[pc - code].counts = (double *) cursor;
         size_t capacity = PCCounts::numCounts(JSOp(*pc));
 #ifdef DEBUG
         scriptCounts.pcCountsVector[pc - code].capacity = capacity;
 #endif
         cursor += capacity * sizeof(double);
         next = pc + GetBytecodeLength(pc);
     }
@@ -1172,21 +1178,23 @@ ScriptSource::substring(JSContext *cx, u
 ScriptSource *
 ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length,
                                bool argumentsNotIncluded, SourceCompressionToken *tok,
                                bool ownSource)
 {
     ScriptSource *ss = static_cast<ScriptSource *>(cx->malloc_(sizeof(*ss)));
     if (!ss)
         return NULL;
-    const size_t memlen = length * sizeof(jschar);
-    ss->data.compressed = static_cast<unsigned char *>(cx->malloc_(memlen));
-    if (!ss->data.compressed) {
-        cx->free_(ss);
-        return NULL;
+    if (!ownSource) {
+        const size_t memlen = length * sizeof(jschar);
+        ss->data.compressed = static_cast<unsigned char *>(cx->malloc_(memlen));
+        if (!ss->data.compressed) {
+            cx->free_(ss);
+            return NULL;
+        }
     }
     ss->next = NULL;
     ss->length_ = length;
     ss->compressedLength = 0;
     ss->marked = ss->onRuntime_ = false;
     ss->argumentsNotIncluded_ = argumentsNotIncluded;
 #ifdef DEBUG
     ss->ready_ = false;
@@ -1809,16 +1817,17 @@ JSScript::fullyInitFromEmitter(JSContext
         PodCopy<uint32_t>(script->closedVars()->vector, &bce->closedVars[0], nClosedVars);
 
     script->bindings.transfer(&bce->sc->bindings);
 
     RootedFunction fun(cx, NULL);
     if (bce->sc->inFunction()) {
         JS_ASSERT(!bce->script->noScriptRval);
         script->isGenerator = bce->sc->funIsGenerator();
+        script->isGeneratorExp = bce->sc->funbox() && bce->sc->funbox()->inGenexpLambda;
         script->setFunction(bce->sc->fun());
     }
 
     /*
      * initScriptCounts updates scriptCountsMap if necessary. The other script
      * maps in JSCompartment are populated lazily.
      */
     if (cx->hasRunOption(JSOPTION_PCCOUNT))
@@ -2284,16 +2293,17 @@ js::CloneScript(JSContext *cx, HandleObj
     }
     dst->cloneHasArray(src);
     dst->strictModeCode = src->strictModeCode;
     dst->explicitUseStrict = src->explicitUseStrict;
     dst->bindingsAccessedDynamically = src->bindingsAccessedDynamically;
     dst->funHasExtensibleScope = src->funHasExtensibleScope;
     dst->hasSingletons = src->hasSingletons;
     dst->isGenerator = src->isGenerator;
+    dst->isGeneratorExp = src->isGeneratorExp;
 
     /*
      * initScriptCounts updates scriptCountsMap if necessary. The other script
      * maps in JSCompartment are populated lazily.
      */
     if (cx->hasRunOption(JSOPTION_PCCOUNT))
         (void) dst->initScriptCounts(cx);
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -535,16 +535,17 @@ struct JSScript : public js::gc::Cell
     bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
     bool            uninlineable:1;   /* script is considered uninlineable by analysis */
 #ifdef JS_METHODJIT
     bool            debugMode:1;      /* script was compiled in debug mode */
     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
 #endif
     bool            callDestroyHook:1;/* need to call destroy hook */
     bool            isGenerator:1;    /* is a generator */
+    bool            isGeneratorExp:1; /* is a generator expression */
     bool            hasScriptCounts:1;/* script has an entry in
                                          JSCompartment::scriptCountsMap */
     bool            hasSourceMap:1;   /* script has an entry in
                                          JSCompartment::sourceMapMap */
     bool            hasDebugScript:1; /* script has an entry in
                                          JSCompartment::debugScriptMap */
 
   private:
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -2384,17 +2384,17 @@ DataViewObject::read(JSContext *cx, Hand
                              JSMSG_MORE_ARGS_NEEDED, method, "0", "s");
         return false;
     }
 
     uint8_t *data;
     if (!getDataPointer(cx, obj, args, sizeof(NativeType), &data))
         return false;
 
-    bool fromLittleEndian = args.length() >= 2 && js_ValueToBoolean(args[1]);
+    bool fromLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
     DataViewIO<NativeType>::fromBuffer(val, data, needToSwapBytes(fromLittleEndian));
     return true;
 }
 
 template <typename NativeType>
 static inline bool
 WebIDLCast(JSContext *cx, const Value &value, NativeType *out)
 {
@@ -2440,17 +2440,17 @@ DataViewObject::write(JSContext *cx, Han
     uint8_t *data;
     if (!getDataPointer(cx, obj, args, sizeof(NativeType), &data))
         return false;
 
     NativeType value;
     if (!WebIDLCast(cx, args[1], &value))
         return false;
 
-    bool toLittleEndian = args.length() >= 3 && js_ValueToBoolean(args[2]);
+    bool toLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
     DataViewIO<NativeType>::toBuffer(data, &value, needToSwapBytes(toLittleEndian));
     return true;
 }
 
 bool
 DataViewObject::getInt8Impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(is(args.thisv()));
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -7933,17 +7933,17 @@ js_StepXMLListFilter(JSContext *cx, JSBo
     } else {
         /* We have iterated at least once. */
         JS_ASSERT(!JSVAL_IS_PRIMITIVE(sp[-2]));
         JS_ASSERT(JSVAL_TO_OBJECT(sp[-2])->getClass() == &js_XMLFilterClass);
         filter = (JSXMLFilter *) JSVAL_TO_OBJECT(sp[-2])->getPrivate();
         JS_ASSERT(filter->kid);
 
         /* Check if the filter expression wants to append the element. */
-        if (js_ValueToBoolean(sp[-1]) &&
+        if (ToBoolean(sp[-1]) &&
             !Append(cx, filter->result, filter->kid)) {
             return JS_FALSE;
         }
     }
 
     /* Do the iteration. */
     filter->kid = filter->cursor.getNext();
     if (!filter->kid) {
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -565,17 +565,17 @@ mjit::Compiler::jsop_relational(JSOp op,
 void
 mjit::Compiler::jsop_not()
 {
     FrameEntry *top = frame.peek(-1);
 
     if (top->isConstant()) {
         const Value &v = top->getValue();
         frame.pop();
-        frame.push(BooleanValue(!js_ValueToBoolean(v)));
+        frame.push(BooleanValue(!ToBoolean(v)));
         return;
     }
 
     if (top->isTypeKnown()) {
         JSValueType type = top->getKnownType();
         switch (type) {
           case JSVAL_TYPE_INT32:
           {
@@ -841,17 +841,17 @@ mjit::Compiler::booleanJumpScript(JSOp o
 }
 
 bool
 mjit::Compiler::jsop_ifneq(JSOp op, jsbytecode *target)
 {
     FrameEntry *fe = frame.peek(-1);
 
     if (fe->isConstant()) {
-        JSBool b = js_ValueToBoolean(fe->getValue());
+        JSBool b = ToBoolean(fe->getValue());
 
         frame.pop();
 
         if (op == JSOP_IFEQ)
             b = !b;
         if (b) {
             if (!frame.syncForBranch(target, Uses(0)))
                 return false;
@@ -868,17 +868,17 @@ mjit::Compiler::jsop_ifneq(JSOp op, jsby
 }
 
 bool
 mjit::Compiler::jsop_andor(JSOp op, jsbytecode *target)
 {
     FrameEntry *fe = frame.peek(-1);
 
     if (fe->isConstant()) {
-        JSBool b = js_ValueToBoolean(fe->getValue());
+        JSBool b = ToBoolean(fe->getValue());
 
         /* Short-circuit. */
         if ((op == JSOP_OR && b == JS_TRUE) ||
             (op == JSOP_AND && b == JS_FALSE)) {
             if (!frame.syncForBranch(target, Uses(0)))
                 return false;
             if (!jumpAndRun(masm.jump(), target))
                 return false;
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -443,23 +443,23 @@ JSBool JS_FASTCALL
 stubs::GreaterEqual(VMFrame &f)
 {
     RELATIONAL(>=);
 }
 
 JSBool JS_FASTCALL
 stubs::ValueToBoolean(VMFrame &f)
 {
-    return js_ValueToBoolean(f.regs.sp[-1]);
+    return ToBoolean(f.regs.sp[-1]);
 }
 
 void JS_FASTCALL
 stubs::Not(VMFrame &f)
 {
-    JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
+    JSBool b = !ToBoolean(f.regs.sp[-1]);
     f.regs.sp[-1].setBoolean(b);
 }
 
 template <bool EQ>
 static inline bool
 StubEqualityOp(VMFrame &f)
 {
     JSContext *cx = f.cx;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1562,17 +1562,17 @@ Debugger::getEnabled(JSContext *cx, unsi
     return true;
 }
 
 JSBool
 Debugger::setEnabled(JSContext *cx, unsigned argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.set enabled", 1);
     THIS_DEBUGGER(cx, argc, vp, "set enabled", args, dbg);
-    bool enabled = js_ValueToBoolean(args[0]);
+    bool enabled = ToBoolean(args[0]);
 
     if (enabled != dbg->enabled) {
         for (Breakpoint *bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
             if (enabled)
                 bp->site->inc(cx->runtime->defaultFreeOp());
             else
                 bp->site->dec(cx->runtime->defaultFreeOp());
         }
@@ -2068,17 +2068,17 @@ class Debugger::ScriptQuery {
                                  "neither undefined nor an integer");
             return false;
         }
 
         /* Check for an 'innermost' property. */
         Value innermostProperty;
         if (!query->getProperty(cx, cx->runtime->atomState.innermostAtom, &innermostProperty))
             return false;
-        innermost = js_ValueToBoolean(innermostProperty);
+        innermost = ToBoolean(innermostProperty);
         if (innermost) {
             /* Technically, we need only check hasLine, but this is clearer. */
             if (url.isUndefined() || !hasLine) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL);
                 return false;
             }
         }
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -20,17 +20,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 123);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 124);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
 
     JSContext *cx() const {
         return context;
--- a/js/xpconnect/src/Makefile.in
+++ b/js/xpconnect/src/Makefile.in
@@ -62,17 +62,16 @@ CPPSRCS		= \
 		$(NULL)
 
 include $(topsrcdir)/config/config.mk
 
 LOCAL_INCLUDES = \
 		-I$(srcdir)/../wrappers \
 		-I$(srcdir)/../loader \
 		-I$(topsrcdir)/caps/include \
-		-I$(topsrcdir)/content/base/public \
 		-I$(topsrcdir)/content/base/src \
 		-I$(topsrcdir)/content/events/src \
 		-I$(topsrcdir)/content/html/content/src \
 		-I$(topsrcdir)/content/html/document/src \
 		-I$(topsrcdir)/content/svg/content/src \
 		-I$(topsrcdir)/layout/style \
 		-I$(topsrcdir)/layout/base \
 		-I$(topsrcdir)/dom/base \
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -9,31 +9,31 @@
 #include "mozilla/Util.h"
 
 #include "xpcprivate.h"
 #include "xpcpublic.h"
 #include "XPCJSMemoryReporter.h"
 #include "WrapperFactory.h"
 #include "dom_quickstubs.h"
 
-#include "Element.h"
 #include "nsIMemoryReporter.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "mozilla/FunctionTimer.h"
 #include "prsystem.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "jsfriendapi.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/Attributes.h"
 
 #include "sampler.h"
 #include "nsJSPrincipals.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -11,17 +11,16 @@ dictionaries = [
      [ 'IDBIndexParameters', 'nsIIDBObjectStore.idl' ],
      [ 'StorageEventInit', 'nsIDOMStorageEvent.idl' ],
      [ 'BlobPropertyBag', 'nsIDOMFile.idl' ],
      [ 'MutationObserverInit', 'nsIDOMMutationObserver.idl' ],
      [ 'SettingsEventInit', 'nsIDOMSettingsManager.idl' ],
      [ 'WifiConnectionInfoEventInit', 'nsIWifiEventInits.idl' ],
      [ 'WifiStatusChangeEventInit', 'nsIWifiEventInits.idl' ],
      [ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
-     [ 'DeviceLightEventInit', 'nsIDOMDeviceLightEvent.idl' ],
      [ 'MozApplicationEventInit', 'nsIDOMApplicationRegistry.idl' ],
      [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
      [ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
      [ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ]
    ]
 
 # include file names
 special_includes = [
--- a/js/xpconnect/src/dictionary_helper_gen.py
+++ b/js/xpconnect/src/dictionary_helper_gen.py
@@ -299,16 +299,18 @@ def write_getter(a, iface, fd):
                  % (get_jsid(a.name), a.name))
     else:
         fd.write("    NS_ENSURE_STATE(JS_GetPropertyById(aCx, aObj, %s, &v));\n"
                  % get_jsid(a.name))
     if realtype.count("bool"):
         fd.write("    JSBool b;\n")
         fd.write("    MOZ_ALWAYS_TRUE(JS_ValueToBoolean(aCx, v, &b));\n")
         fd.write("    aDict.%s = b;\n" % a.name)
+    elif realtype.count("PRUint32"):
+        fd.write("    NS_ENSURE_STATE(JS_ValueToECMAUint32(aCx, v, &aDict.%s));\n" % a.name)
     elif realtype.count("PRInt32"):
         fd.write("    NS_ENSURE_STATE(JS_ValueToECMAInt32(aCx, v, &aDict.%s));\n" % a.name)
     elif realtype.count("double"):
         fd.write("    NS_ENSURE_STATE(JS_ValueToNumber(aCx, v, &aDict.%s));\n" % a.name)
     elif realtype.count("float"):
         fd.write("    double d;\n")
         fd.write("    NS_ENSURE_STATE(JS_ValueToNumber(aCx, v, &d));")
         fd.write("    aDict.%s = (float) d;\n" % a.name)
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -10,17 +10,19 @@
 simple_events = [
     'DeviceProximityEvent',
     'UserProximityEvent',
     'CustomEvent',
     'PageTransitionEvent',
     'PopStateEvent',
     'HashChangeEvent',
     'CloseEvent',
-    'MozContactChangeEvent'
+    'MozContactChangeEvent',
+    'DeviceOrientationEvent',
+    'DeviceLightEvent'
   ]
 
 """ include file names """
 special_includes = [
     'DictionaryHelpers.h',
     'nsContentUtils.h'
   ]
 
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2625,16 +2625,20 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
     items.SwapElements(entry->mItems);
     commonClipCount = entry->mCommonClipCount;
     containerLayerFrame = entry->mContainerLayerFrame;
     // Later after this point, due to calls to DidEndTransaction
     // for temporary layer managers, mThebesLayerItems can change,
     // so 'entry' could become invalid.
   }
 
+  if (!containerLayerFrame) {
+    return;
+  }
+
   ThebesDisplayItemLayerUserData* userData =
     static_cast<ThebesDisplayItemLayerUserData*>
       (aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
   NS_ASSERTION(userData, "where did our user data go?");
   if (NS_GET_A(userData->mForcedBackgroundColor) > 0) {
     nsIntRect r = aLayer->GetVisibleRegion().GetBounds();
     aContext->NewPath();
     aContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height));
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/770381-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style id="s"></style>
+<script>
+function boom() { document.getElementById("s").textContent = "div { opacity: 0.5; }"; }
+</script>
+</head>
+<body onload="document.documentElement.offsetHeight; boom();">
+<div><div>X</div></div>
+</body>
+</html>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -353,8 +353,9 @@ load 722137.html
 load 725535.html
 load 727601.html
 skip-if(Android&&!browserIsRemote) asserts(0-2) pref(dom.disable_open_during_load,false) load 735943.html # the assertion is bug 735966, for android bug 760271
 asserts(0-2) load 736389-1.xhtml # sometimes the above assertions are delayed and is reported on this test instead
 asserts-if(winWidget,0-2) load 736924-1.html # bug 738803
 load 749816-1.html
 load 763223-1.html
 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,100) load 763702.xhtml
+load 770381-1.html
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -60,16 +60,17 @@ nsDisplayListBuilder::nsDisplayListBuild
       mIncludeAllOutOfFlows(false),
       mSelectedFramesOnly(false),
       mAccurateVisibleRegions(false),
       mInTransform(false),
       mSyncDecodeImages(false),
       mIsPaintingToWindow(false),
       mHasDisplayPort(false),
       mHasFixedItems(false),
+      mIsInFixedPosition(false),
       mIsCompositingCheap(false)
 {
   MOZ_COUNT_CTOR(nsDisplayListBuilder);
   PL_InitArenaPool(&mPool, "displayListArena", 1024,
                    NS_MAX(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
 
   nsPresContext* pc = aReferenceFrame->PresContext();
   nsIPresShell *shell = pc->PresShell();
@@ -2067,18 +2068,20 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayL
   nsRefPtr<Layer> layer = GetLayerBuilderForManager(aManager)->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nsnull);
   return layer.forget();
 }
 
 nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
                                                nsIFrame* aFrame,
+                                               nsIFrame* aFixedPosFrame,
                                                nsDisplayList* aList)
-    : nsDisplayOwnLayer(aBuilder, aFrame, aList) {
+    : nsDisplayOwnLayer(aBuilder, aFrame, aList)
+    , mFixedPosFrame(aFixedPosFrame) {
   MOZ_COUNT_CTOR(nsDisplayFixedPosition);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayFixedPosition::~nsDisplayFixedPosition() {
   MOZ_COUNT_DTOR(nsDisplayFixedPosition);
 }
 #endif
@@ -2089,17 +2092,17 @@ nsDisplayFixedPosition::BuildLayer(nsDis
                                    const ContainerParameters& aContainerParameters) {
   nsRefPtr<Layer> layer =
     nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
 
   // Work out the anchor point for this fixed position layer. We assume that
   // any positioning set (left/top/right/bottom) indicates that the
   // corresponding side of its container should be the anchor point,
   // defaulting to top-left.
-  nsIFrame* viewportFrame = mFrame->GetParent();
+  nsIFrame* viewportFrame = mFixedPosFrame->GetParent();
   nsPresContext *presContext = viewportFrame->PresContext();
 
   // Fixed position frames are reflowed into the scroll-port size if one has
   // been set.
   nsSize containingBlockSize = viewportFrame->GetSize();
   if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
     containingBlockSize = presContext->PresShell()->
       GetScrollPositionClampingScrollPortSize();
@@ -2116,17 +2119,17 @@ nsDisplayFixedPosition::BuildLayer(nsDis
                        aContainerParameters.mYScale,
                      NSAppUnitsToFloatPixels(containingBlockSize.width, factor) *
                        aContainerParameters.mXScale,
                      NSAppUnitsToFloatPixels(containingBlockSize.height, factor) *
                        aContainerParameters.mYScale);
 
   gfxPoint anchor(anchorRect.x, anchorRect.y);
 
-  const nsStylePosition* position = mFrame->GetStylePosition();
+  const nsStylePosition* position = mFixedPosFrame->GetStylePosition();
   if (position->mOffset.GetRightUnit() != eStyleUnit_Auto)
     anchor.x = anchorRect.XMost();
   if (position->mOffset.GetBottomUnit() != eStyleUnit_Auto)
     anchor.y = anchorRect.YMost();
 
   layer->SetFixedPositionAnchor(anchor);
 
   return layer.forget();
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -217,16 +217,22 @@ public:
    */
   bool GetHadToIgnorePaintSuppression() { return mHadToIgnoreSuppression; }
   /**
    * Call this if we're doing normal painting to the window.
    */
   void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; }
   bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
 
+  /**
+   * @return Returns if the builder is currently building an
+   * nsDisplayFixedPosition sub-tree.
+   */
+  bool IsInFixedPosition() const { return mIsInFixedPosition; }
+
   bool SetIsCompositingCheap(bool aCompositingCheap) { 
     bool temp = mIsCompositingCheap; 
     mIsCompositingCheap = aCompositingCheap;
     return temp;
   }
   bool IsCompositingCheap() const { return mIsCompositingCheap; }
   /**
    * Display the caret if needed.
@@ -386,54 +392,61 @@ public:
    * Allocate memory in our arena. It will only be freed when this display list
    * builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
    * destructors are called as soon as the item is no longer used.
    */
   void* Allocate(size_t aSize);
   
   /**
    * A helper class to temporarily set the value of
-   * mIsAtRootOfPseudoStackingContext and temporarily update
-   * mCachedOffsetFrame/mCachedOffset from a frame to its child.
+   * mIsAtRootOfPseudoStackingContext and mIsInFixedPosition, and temporarily
+   * update mCachedOffsetFrame/mCachedOffset from a frame to its child.
    */
   class AutoBuildingDisplayList;
   friend class AutoBuildingDisplayList;
   class AutoBuildingDisplayList {
   public:
     AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, bool aIsRoot)
       : mBuilder(aBuilder),
         mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame),
         mPrevCachedOffset(aBuilder->mCachedOffset),
         mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext) {
       aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
     }
     AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder,
-                            nsIFrame* aForChild, bool aIsRoot)
+                            nsIFrame* aForChild, bool aIsRoot,
+                            bool aIsInFixedPosition)
       : mBuilder(aBuilder),
         mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame),
         mPrevCachedOffset(aBuilder->mCachedOffset),
-        mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext) {
+        mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext),
+        mPrevIsInFixedPosition(aBuilder->mIsInFixedPosition) {
       if (mPrevCachedOffsetFrame == aForChild->GetParent()) {
         aBuilder->mCachedOffset += aForChild->GetPosition();
       } else {
         aBuilder->mCachedOffset = aForChild->GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
       }
       aBuilder->mCachedOffsetFrame = aForChild;
       aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot;
+      if (aIsInFixedPosition) {
+        aBuilder->mIsInFixedPosition = aIsInFixedPosition;
+      }
     }
     ~AutoBuildingDisplayList() {
       mBuilder->mCachedOffsetFrame = mPrevCachedOffsetFrame;
       mBuilder->mCachedOffset = mPrevCachedOffset;
       mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext;
+      mBuilder->mIsInFixedPosition = mPrevIsInFixedPosition;
     }
   private:
     nsDisplayListBuilder* mBuilder;
     const nsIFrame*       mPrevCachedOffsetFrame;
     nsPoint               mPrevCachedOffset;
     bool                  mPrevIsAtRootOfPseudoStackingContext;
+    bool                  mPrevIsInFixedPosition;
   };
 
   /**
    * A helper class to temporarily set the value of mInTransform.
    */
   class AutoInTransformSetter;
   friend class AutoInTransformSetter;
   class AutoInTransformSetter {
@@ -530,16 +543,17 @@ private:
   bool                           mAccurateVisibleRegions;
   // True when we're building a display list that's directly or indirectly
   // under an nsDisplayTransform
   bool                           mInTransform;
   bool                           mSyncDecodeImages;
   bool                           mIsPaintingToWindow;
   bool                           mHasDisplayPort;
   bool                           mHasFixedItems;
+  bool                           mIsInFixedPosition;
   bool                           mIsCompositingCheap;
 };
 
 class nsDisplayItem;
 class nsDisplayList;
 /**
  * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
  * nsDisplayItemLink holds the link. The lists are linked from lowest to
@@ -1915,25 +1929,28 @@ public:
 /**
  * A display item used to represent fixed position elements. This will ensure
  * the contents gets its own layer, and that the built layer will have
  * position-related metadata set on it.
  */
 class nsDisplayFixedPosition : public nsDisplayOwnLayer {
 public:
   nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-                         nsDisplayList* aList);
+                         nsIFrame* aFixedPosFrame, nsDisplayList* aList);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayFixedPosition();
 #endif
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters);
   NS_DISPLAY_DECL_NAME("FixedPosition", TYPE_FIXED_POSITION)
+
+protected:
+  nsIFrame* mFixedPosFrame;
 };
 
 /**
  * This potentially creates a layer for the given list of items, whose
  * visibility is determined by the displayport for the given frame instead of
  * what is passed in to ComputeVisibility.
  *
  * Here in content, we can use this to render more content than is actually
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2098,18 +2098,25 @@ nsIFrame::BuildDisplayListForChild(nsDis
   if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating()) ||
       ((disp->mClipFlags & NS_STYLE_CLIP_RECT) &&
        IsSVGContentWithCSSClip(this)) ||
       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
     // If you change this, also change IsPseudoStackingContextFromStyle()
     pseudoStackingContext = true;
   }
 
+  // This controls later whether we build an nsDisplayWrapList or an
+  // nsDisplayFixedPosition. We check if we're already building a fixed-pos
+  // item and disallow nesting, to prevent the situation of bug #769541
+  // occurring.
+  bool buildFixedPositionItem = disp->mPosition == NS_STYLE_POSITION_FIXED
+    && !child->GetParent()->GetParent() && !isSVG && !aBuilder->IsInFixedPosition();
+
   nsDisplayListBuilder::AutoBuildingDisplayList
-    buildingForChild(aBuilder, child, pseudoStackingContext);
+    buildingForChild(aBuilder, child, pseudoStackingContext, buildFixedPositionItem);
 
   nsRect overflowClip;
   nscoord overflowClipRadii[8];
   bool applyOverflowClip =
     ApplyOverflowClipping(aBuilder, child, disp, &overflowClip);
   if (applyOverflowClip) {
     child->GetPaddingBoxBorderRadii(overflowClipRadii);
   }
@@ -2199,28 +2206,40 @@ nsIFrame::BuildDisplayListForChild(nsDis
   if (isPositioned || isVisuallyAtomic ||
       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
     // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
     // go in this level.
     if (!list.IsEmpty()) {
       // Make sure the root of a fixed position frame sub-tree gets the
       // correct displaylist item type.
       nsDisplayItem* item;
-      if (!isSVG && !child->GetParent()->GetParent() &&
-          disp->mPosition == NS_STYLE_POSITION_FIXED) {
-        item = new (aBuilder) nsDisplayFixedPosition(aBuilder, child, &list);
+      if (buildFixedPositionItem) {
+        item = new (aBuilder) nsDisplayFixedPosition(aBuilder, child, child, &list);
       } else {
         item = new (aBuilder) nsDisplayWrapList(aBuilder, child, &list);
       }
       if (isSVG) {
         rv = aLists.Content()->AppendNewToTop(item);
       } else {
         rv = aLists.PositionedDescendants()->AppendNewToTop(item);
       }
       NS_ENSURE_SUCCESS(rv, rv);
+
+      // Make sure that extra positioned descendants don't escape having
+      // their fixed-position metadata applied to them.
+      if (buildFixedPositionItem) {
+        while (!extraPositionedDescendants.IsEmpty()) {
+          item = extraPositionedDescendants.RemoveBottom();
+          nsDisplayList fixedPosDescendantList;
+          fixedPosDescendantList.AppendToTop(item);
+          aLists.PositionedDescendants()->AppendNewToTop(
+              new (aBuilder) nsDisplayFixedPosition(aBuilder, item->GetUnderlyingFrame(),
+                                                    child, &fixedPosDescendantList));
+        }
+      }
     }
   } else if (!isSVG && disp->IsFloating()) {
     if (!list.IsEmpty()) {
       rv = aLists.Floats()->AppendNewToTop(new (aBuilder)
           nsDisplayWrapList(aBuilder, child, &list));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   } else {
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -552,16 +552,17 @@ RenderFrameParent::ContentViewScaleChang
 {
   // Since the scale has changed for a view, it and its descendents need their
   // shadow-space attributes updated. It's easiest to rebuild the view map.
   BuildViewMap();
 }
 
 void
 RenderFrameParent::ShadowLayersUpdated(ShadowLayersParent* aLayerTree,
+                                       const TargetConfig& aTargetConfig,
                                        bool isFirstPaint)
 {
   // View map must only contain views that are associated with the current
   // shadow layer tree. We must always update the map when shadow layers
   // are updated.
   BuildViewMap();
 
   TriggerRepaint();
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -22,30 +22,32 @@ class nsSubDocumentFrame;
 
 namespace mozilla {
 
 class InputEvent;
 
 namespace layers {
 class AsyncPanZoomController;
 class GestureEventListener;
+class TargetConfig;
 class ShadowLayersParent;
 }
 
 namespace layout {
 
 class RemoteContentController;
 
 class RenderFrameParent : public PRenderFrameParent,
                           public mozilla::layers::ShadowLayersManager
 {
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ContainerLayer ContainerLayer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
+  typedef mozilla::layers::TargetConfig TargetConfig;
   typedef mozilla::layers::ShadowLayersParent ShadowLayersParent;
   typedef FrameMetrics::ViewID ViewID;
 
 public:
   typedef std::map<ViewID, nsRefPtr<nsContentView> > ViewMap;
 
   /**
    * Select the desired scrolling behavior.  If ASYNC_PAN_ZOOM is
@@ -65,16 +67,17 @@ public:
    * Helper function for getting a non-owning reference to a scrollable.
    * @param aId The ID of the frame.
    */
   nsContentView* GetContentView(ViewID aId = FrameMetrics::ROOT_SCROLL_ID);
 
   void ContentViewScaleChanged(nsContentView* aView);
 
   virtual void ShadowLayersUpdated(ShadowLayersParent* aLayerTree,
+                                   const TargetConfig& aTargetConfig,
                                    bool isFirstPaint) MOZ_OVERRIDE;
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
                               nsSubDocumentFrame* aFrame,
                               const nsRect& aDirtyRect,
                               const nsDisplayListSet& aLists);
 
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-matching/arial-arabic-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Bug 769475 - test for italicized Arabic script in Arial</title>
+<style type="text/css">
+body {
+  font-family: arial, serif;
+  font-size: 36px;
+  line-height: 72px;
+}
+span {
+  color: white;
+}
+</style>
+</head>
+<body lang="ar">
+<!-- the white span should have the same width whether it's italicized or not,
+  -- as Arial does not have Arabic characters in the italic face but we should
+  -- apply synthetic italic to the regular face, NOT fall back to a different
+  -- family from prefs.
+  -->
+<div>العربي <span>العربي</span> العربي</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/font-matching/arial-arabic.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Bug 769475 - test for italicized Arabic script in Arial</title>
+<style type="text/css">
+body {
+  font-family: arial, serif;
+  font-size: 36px;
+  line-height: 72px;
+}
+span {
+  font-style: italic;
+  color: white;
+}
+</style>
+</head>
+<body lang="ar">
+<!-- the white span should have the same width whether it's italicized or not,
+  -- as Arial does not have Arabic characters in the italic face but we should
+  -- apply synthetic italic to the regular face, NOT fall back to a different
+  -- family from prefs.
+  -->
+<div>العربي <span>العربي</span> العربي</div>
+</body>
+</html>
--- a/layout/reftests/font-matching/reftest.list
+++ b/layout/reftests/font-matching/reftest.list
@@ -76,8 +76,12 @@ HTTP(..) == font-stretch-1.html font-str
 != synthetic-style-2.html synthetic-style-2-notref.html
 
 # Bug 765906 - synthetic bold should be used if necessary together with system fallback.
 # **NOTE** we skip these on Linux because of bug 769659.
 # test 1 uses Cherokee; expected to pass on OS X and Win7
 random-if(!(cocoaWidget||/^Windows\x20NT\x206\.1/.test(http.oscpu))) skip-if(gtk2Widget) != bold-system-fallback-1.html bold-system-fallback-1-notref.html
 # test 2 uses Chess symbols; expected to pass on Android
 random-if(!Android) skip-if(gtk2Widget) != bold-system-fallback-2.html bold-system-fallback-2-notref.html
+
+# Bug 769475 - applying 'italic' to Arabic text in Arial should NOT change family or metrics.
+# Expected to pass on MacOSX and Windows; other platforms unknown, depending on font availability.
+random-if(!(cocoaWidget||winWidget)) == arial-arabic.html arial-arabic-ref.html
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -124,18 +124,17 @@ nsComputedDOMStyle::nsComputedDOMStyle(d
     if (!haveTwoColons &&
         !nsCSSPseudoElements::IsCSS2PseudoElement(mPseudo)) {
       // XXXbz I'd really rather we threw an exception or something, but
       // the DOM spec sucks.
       mPseudo = nsnull;
     }
   }
 
-  nsPresContext *presCtx = aPresShell->GetPresContext();
-  MOZ_ASSERT(presCtx);
+  MOZ_ASSERT(aPresShell->GetPresContext());
 }
 
 
 nsComputedDOMStyle::~nsComputedDOMStyle()
 {
 }
 
 void
--- a/media/libsydneyaudio/src/sydney_audio_android.c
+++ b/media/libsydneyaudio/src/sydney_audio_android.c
@@ -376,18 +376,16 @@ sa_stream_get_write_size(sa_stream_t *s,
 
 int
 sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
 
   if (s == NULL || s->output_unit == NULL) {
     return SA_ERROR_NO_INIT;
   }
 
-  ALOG("%p - get position", s);
-
   JNIEnv *jenv = GetJNIForThread();
   *pos  = (*jenv)->CallIntMethod(jenv, s->output_unit, at.getpos);
 
   /* android returns number of frames, so:
      position = frames * (PCM_16_BIT == 2 bytes) * channels
   */
   *pos *= s->channels * sizeof(int16_t);
   return SA_SUCCESS;
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -531,16 +531,19 @@ abstract public class BrowserApp extends
 
         MenuInflater inflater = getMenuInflater();
         inflater.inflate(R.menu.gecko_menu, mMenu);
         return true;
     }
 
     @Override
     public void openOptionsMenu() {
+        if (!hasTabsSideBar() && areTabsShown())
+            return;
+
         // Scroll custom menu to the top
         if (mMenuPanel != null)
             mMenuPanel.scrollTo(0, 0);
 
         if (!mBrowserToolbar.openOptionsMenu())
             super.openOptionsMenu();
     }
 
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -215,19 +215,16 @@ public class BrowserToolbar implements V
         mMenu = (ImageButton) mLayout.findViewById(R.id.menu);
         mActionItemBar = (LinearLayout) mLayout.findViewById(R.id.menu_items);
         mHasSoftMenuButton = !GeckoApp.mAppContext.hasPermanentMenuKey();
 
         if (mHasSoftMenuButton) {
             mMenu.setVisibility(View.VISIBLE);
             mMenu.setOnClickListener(new Button.OnClickListener() {
                 public void onClick(View view) {
-                    if (!GeckoApp.mAppContext.hasTabsSideBar() && GeckoApp.mAppContext.areTabsShown())
-                        return;
-
                     GeckoApp.mAppContext.openOptionsMenu();
                 }
             });
         }
 
         if (Build.VERSION.SDK_INT >= 11) {
             View panel = GeckoApp.mAppContext.getMenuPanel();
 
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -524,30 +524,23 @@ abstract public class GeckoApp
         public MenuPanel(Context context, AttributeSet attrs) {
             super(context, attrs);
             setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                                                        ViewGroup.LayoutParams.WRAP_CONTENT));
         }
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            if (getChildCount() == 0) {
-                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-                return;
-            }
-
-            int restrictedHeightSpec;
-            int childHeight = getChildAt(0).getHeight();
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
             DisplayMetrics metrics = new DisplayMetrics();
             ((Activity) GeckoApp.mAppContext).getWindowManager().getDefaultDisplay().getMetrics(metrics);
 
             // heightPixels changes during rotation.
-            int preferredHeight = (int) (0.75 * metrics.heightPixels);
-            restrictedHeightSpec = MeasureSpec.makeMeasureSpec(childHeight <= preferredHeight ? childHeight : preferredHeight, MeasureSpec.EXACTLY);
+            int restrictedHeightSpec = MeasureSpec.makeMeasureSpec((int) (0.75 * metrics.heightPixels), MeasureSpec.AT_MOST);
 
             super.onMeasure(widthMeasureSpec, restrictedHeightSpec);
         }
 
         @Override
         public boolean dispatchPopulateAccessibilityEvent (AccessibilityEvent event) {
             if (Build.VERSION.SDK_INT >= 14) // Build.VERSION_CODES.ICE_CREAM_SANDWICH
                 onPopulateAccessibilityEvent(event);
@@ -706,16 +699,27 @@ abstract public class GeckoApp
                     Log.e(LOGTAG, "error building json arguments");
                 }
                 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("DesktopMode:Change", args.toString()));
                 return true;
             default:
                 return super.onOptionsItemSelected(item);
         }
     }
+ 
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        // Custom Menu should be opened when hardware menu key is pressed.
+        if (Build.VERSION.SDK_INT >= 11 && keyCode == KeyEvent.KEYCODE_MENU) {
+            openOptionsMenu();
+            return true;
+        }
+
+        return super.onKeyDown(keyCode, event);
+    }
 
     private void shareCurrentUrl() {
       Tab tab = Tabs.getInstance().getSelectedTab();
       if (tab == null)
         return;
 
       String url = tab.getURL();
       if (url == null)
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -38,17 +38,17 @@ public final class Tab {
     private int mId;
     private String mUrl;
     private String mTitle;
     private Drawable mFavicon;
     private String mFaviconUrl;
     private int mFaviconSize;
     private JSONObject mIdentityData;
     private boolean mReaderEnabled;
-    private Drawable mThumbnail;
+    private BitmapDrawable mThumbnail;
     private int mHistoryIndex;
     private int mHistorySize;
     private int mParentId;
     private boolean mExternal;
     private boolean mBookmark;
     private boolean mReadingListItem;
     private HashMap<String, DoorHanger> mDoorHangers;
     private long mFaviconLoadId;
@@ -186,20 +186,19 @@ public final class Tab {
     }
 
     public void updateThumbnail(final Bitmap b) {
         final Tab tab = this;
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
                 if (b != null) {
                     try {
+                        mThumbnail = new BitmapDrawable(b);
                         if (mState == Tab.STATE_SUCCESS)
-                            saveThumbnailToDB(new BitmapDrawable(b));
-
-                        mThumbnail = new BitmapDrawable(b);
+                            saveThumbnailToDB();
                     } catch (OutOfMemoryError oom) {
                         Log.e(LOGTAG, "Unable to create/scale bitmap", oom);
                         mThumbnail = null;
                     }
                 } else {
                     mThumbnail = null;
                 }
                 GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
@@ -584,23 +583,23 @@ public final class Tab {
             if (mHistorySize < 0 || mHistoryIndex < -1) {
                 Log.e(LOGTAG, "Unexpected history state: index = " + mHistoryIndex + ", size = " + mHistorySize);
                 mHistorySize = 0;
                 mHistoryIndex = -1;
             }
         }
     }
 
-    private void saveThumbnailToDB(BitmapDrawable thumbnail) {
+    private void saveThumbnailToDB() {
         try {
             String url = getURL();
             if (url == null)
                 return;
 
-            BrowserDB.updateThumbnailForUrl(mContentResolver, url, thumbnail);
+            BrowserDB.updateThumbnailForUrl(mContentResolver, url, mThumbnail);
         } catch (Exception e) {
             // ignore
         }
     }
 
     public void addPluginView(View view) {
         mPluginViews.add(view);
     }
--- a/mobile/android/base/sync/setup/activities/SetupSuccessActivity.java
+++ b/mobile/android/base/sync/setup/activities/SetupSuccessActivity.java
@@ -41,17 +41,14 @@ public class SetupSuccessActivity extend
     super.onDestroy();
   }
 
   /* Click Handlers */
   public void settingsClickHandler(View target) {
     SyncAccounts.openSyncSettings(this);
   }
 
-
   public void launchBrowser(View target) {
     Intent intent = new Intent(Intent.ACTION_MAIN);
     intent.setClassName(GlobalConstants.BROWSER_INTENT_PACKAGE, GlobalConstants.BROWSER_INTENT_CLASS);
-    // Start Fennec as a new task. If Fennec is already running, bring it to the front.
-    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     startActivity(intent);
   }
 }
--- a/mobile/android/base/sync/setup/activities/SetupSyncActivity.java
+++ b/mobile/android/base/sync/setup/activities/SetupSyncActivity.java
@@ -131,28 +131,28 @@ public class SetupSyncActivity extends A
       if (!isSetup) {
         Logger.debug(LOG_TAG, "Account exists; Pair a Device started.");
         pairWithPin = true;
         displayPairWithPin();
         return;
       }
     }
 
-    final Activity setupActivity = this;
     runOnUiThread(new Runnable() {
       @Override
       public void run() {
         Logger.debug(LOG_TAG, "Only one account supported. Redirecting.");
         // Display toast for "Only one account supported."
         // Redirect to account management.
         Toast toast = Toast.makeText(mContext,
             R.string.sync_notification_oneaccount, Toast.LENGTH_LONG);
         toast.show();
 
-        SyncAccounts.openSyncSettings(setupActivity);
+        // Setting up Sync when an existing account exists only happens from Settings,
+        // so we can safely finish() the activity to return to Settings.
         finish();
       }
     });
   }
 
 
   @Override
   public void onPause() {
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3222,17 +3222,17 @@ var BrowserEventHandler = {
   init: function init() {
     Services.obs.addObserver(this, "Gesture:SingleTap", false);
     Services.obs.addObserver(this, "Gesture:CancelTouch", false);
     Services.obs.addObserver(this, "Gesture:DoubleTap", false);
     Services.obs.addObserver(this, "Gesture:Scroll", false);
     Services.obs.addObserver(this, "dom-touch-listener-added", false);
 
     BrowserApp.deck.addEventListener("DOMUpdatePageReport", PopupBlockerObserver.onUpdatePageReport, false);
-    BrowserApp.deck.addEventListener("touchstart", this, false);
+    BrowserApp.deck.addEventListener("touchstart", this, true);
     BrowserApp.deck.addEventListener("click", SelectHelper, true);
   },
 
   handleEvent: function(aEvent) {
     if (!BrowserApp.isBrowserContentDocumentDisplayed() || aEvent.touches.length > 1 || aEvent.defaultPrevented)
       return;
 
     let closest = aEvent.target;
@@ -3495,40 +3495,40 @@ var BrowserEventHandler = {
     // the element can be out of the aX/aY point because of the touch radius
     // if outside, we gracefully move the touch point to the edge of the element
     if (!(aElement instanceof HTMLHtmlElement)) {
       let isTouchClick = true;
       let rects = ElementTouchHelper.getContentClientRects(aElement);
       for (let i = 0; i < rects.length; i++) {
         let rect = rects[i];
         let inBounds =
-          (aX> rect.left  && aX < (rect.left + rect.width)) &&
+          (aX > rect.left && aX < (rect.left + rect.width)) &&
           (aY > rect.top && aY < (rect.top + rect.height));
         if (inBounds) {
           isTouchClick = false;
           break;
         }
       }
 
       if (isTouchClick) {
         let rect = rects[0];
         if (rect.width != 0 || rect.height != 0) {
-          aX = Math.min(rect.left + rect.width, Math.max(rect.left, aX));
-          aY = Math.min(rect.top + rect.height, Math.max(rect.top,  aY));
+          aX = Math.min(Math.floor(rect.left + rect.width), Math.max(Math.ceil(rect.left), aX));
+          aY = Math.min(Math.floor(rect.top + rect.height), Math.max(Math.ceil(rect.top),  aY));
         }
       }
     }
     return [aX, aY];
   },
 
   _sendMouseEvent: function _sendMouseEvent(aName, aElement, aX, aY) {
     let window = aElement.ownerDocument.defaultView;
     try {
       let cwu = window.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-      cwu.sendMouseEventToWindow(aName, Math.round(aX), Math.round(aY), 0, 1, 0, true);
+      cwu.sendMouseEventToWindow(aName, aX, aY, 0, 1, 0, true);
     } catch(e) {
       Cu.reportError(e);
     }
   },
 
   _hasScrollableOverflow: function(elem) {
     var win = elem.ownerDocument.defaultView;
     if (!win)
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -587,28 +587,18 @@ nsIOService::LookupProxyInfo(nsIURI *aUR
     nsCOMPtr<nsIProxyInfo> pi;
 
     if (!mProxyService) {
         mProxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
         if (!mProxyService)
             NS_WARNING("failed to get protocol proxy service");
     }
     if (mProxyService) {
-        PRUint32 flags = 0;
-        if (aScheme->EqualsLiteral("http") || aScheme->EqualsLiteral("https"))
-            flags = nsIProtocolProxyService::RESOLVE_NON_BLOCKING;
         rv = mProxyService->Resolve(aProxyURI ? aProxyURI : aURI, aProxyFlags,
                                     getter_AddRefs(pi));
-        if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
-            // Use an UNKNOWN proxy to defer resolution and avoid blocking.
-            rv = mProxyService->NewProxyInfo(NS_LITERAL_CSTRING("unknown"),
-                                             NS_LITERAL_CSTRING(""),
-                                             -1, 0, 0, nsnull,
-                                             getter_AddRefs(pi));
-        }
         if (NS_FAILED(rv))
             pi = nsnull;
     }
     pi.forget(outPI);
 }
 
 
 NS_IMETHODIMP
--- a/netwerk/base/src/nsProtocolProxyService.cpp
+++ b/netwerk/base/src/nsProtocolProxyService.cpp
@@ -905,18 +905,17 @@ nsProtocolProxyService::NewProxyInfo(con
                                      PRUint32 aFailoverTimeout,
                                      nsIProxyInfo *aFailoverProxy,
                                      nsIProxyInfo **aResult)
 {
     static const char *types[] = {
         kProxyType_HTTP,
         kProxyType_SOCKS,
         kProxyType_SOCKS4,
-        kProxyType_DIRECT,
-        kProxyType_UNKNOWN
+        kProxyType_DIRECT
     };
 
     // resolve type; this allows us to avoid copying the type string into each
     // proxy info instance.  we just reference the string literals directly :)
     const char *type = nsnull;
     for (PRUint32 i=0; i<ArrayLength(types); ++i) {
         if (aType.LowerCaseEqualsASCII(types[i])) {
             type = types[i];
--- a/netwerk/mime/nsMIMEHeaderParamImpl.cpp
+++ b/netwerk/mime/nsMIMEHeaderParamImpl.cpp
@@ -93,17 +93,17 @@ nsMIMEHeaderParamImpl::DoGetParameter(co
     if (!aFallbackCharset.IsEmpty())
     {
         nsCAutoString str2;
         nsCOMPtr<nsIUTF8ConverterService> 
           cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID));
         if (cvtUTF8 &&
             NS_SUCCEEDED(cvtUTF8->ConvertStringToUTF8(str1, 
                 PromiseFlatCString(aFallbackCharset).get(), false, true,
-                                   str2))) {
+                                   1, str2))) {
           CopyUTF8toUTF16(str2, aResult);
           return NS_OK;
         }
     }
 
     if (IsUTF8(str1)) {
       CopyUTF8toUTF16(str1, aResult);
       return NS_OK;
@@ -287,17 +287,17 @@ bool IsValidOctetSequenceForCharset(nsAC
   }
 
   nsCAutoString tmpRaw;
   tmpRaw.Assign(aOctets);
   nsCAutoString tmpDecoded;
 
   nsresult rv = cvtUTF8->ConvertStringToUTF8(tmpRaw,
                                              PromiseFlatCString(aCharset).get(),
-                                             false, false, tmpDecoded);
+                                             false, false, 1, tmpDecoded);
 
   if (rv != NS_OK) {
     // we can't decode; charset may be unsupported, or the octet sequence
     // is broken (illegal or incomplete octet sequence contained)
     NS_WARNING("RFC2231/5987 parameter value does not decode according to specified charset\n");
     return false;
   }
 
@@ -847,17 +847,17 @@ nsMIMEHeaderParamImpl::DecodeRFC5987Para
 
   // finally convert octet sequence to UTF-8 and be done
   nsresult rv = NS_OK;
   nsCOMPtr<nsIUTF8ConverterService> cvtUTF8 =
     do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCAutoString utf8;
-  rv = cvtUTF8->ConvertStringToUTF8(value, charset.get(), true, false, utf8);
+  rv = cvtUTF8->ConvertStringToUTF8(value, charset.get(), true, false, 1, utf8);
   NS_ENSURE_SUCCESS(rv, rv);
 
   CopyUTF8toUTF16(utf8, aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsMIMEHeaderParamImpl::DecodeParameter(const nsACString& aParamValue,
@@ -869,17 +869,17 @@ nsMIMEHeaderParamImpl::DecodeParameter(c
   aResult.Truncate();
   // If aCharset is given, aParamValue was obtained from RFC2231/5987 
   // encoding and we're pretty sure that it's in aCharset.
   if (aCharset && *aCharset)
   {
     nsCOMPtr<nsIUTF8ConverterService> cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID));
     if (cvtUTF8)
       return cvtUTF8->ConvertStringToUTF8(aParamValue, aCharset,
-          true, true, aResult);
+          true, true, 1, aResult);
   }
 
   const nsAFlatCString& param = PromiseFlatCString(aParamValue);
   nsCAutoString unQuoted;
   nsACString::const_iterator s, e;
   param.BeginReading(s);
   param.EndReading(e);
 
@@ -1049,17 +1049,18 @@ void CopyRawHeader(const char *aInput, P
 
   // If not UTF-8, treat as default charset
   nsCOMPtr<nsIUTF8ConverterService> 
     cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID));
   nsCAutoString utf8Text;
   if (cvtUTF8 &&
       NS_SUCCEEDED(
       cvtUTF8->ConvertStringToUTF8(Substring(aInput, aInput + aLen), 
-      aDefaultCharset, skipCheck, true, utf8Text))) {
+                                   aDefaultCharset, skipCheck, true, 1,
+                                   utf8Text))) {
     aOutput.Append(utf8Text);
   } else { // replace each octet with Unicode replacement char in UTF-8.
     for (PRUint32 i = 0; i < aLen; i++) {
       c = PRUint8(*aInput++);
       if (c & 0x80)
         aOutput.Append(REPLACEMENT_CHAR);
       else
         aOutput.Append(char(c));
@@ -1182,17 +1183,19 @@ nsresult DecodeRFC2047Str(const char *aH
     {
       nsCOMPtr<nsIUTF8ConverterService> 
         cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID));
       nsCAutoString utf8Text;
       // skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset.
       if (cvtUTF8 &&
           NS_SUCCEEDED(
             cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText),
-            charset, IS_7BIT_NON_ASCII_CHARSET(charset), true, utf8Text))) {
+                                         charset,
+                                         IS_7BIT_NON_ASCII_CHARSET(charset),
+                                         true, 1, utf8Text))) {
         aResult.Append(utf8Text);
       } else {
         aResult.Append(REPLACEMENT_CHAR);
       }
     }
     PR_Free(decodedText);
     begin = r + 2;
     isLastEncodedWord = 1;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1517,22 +1517,21 @@ HttpBaseChannel::IsSafeMethod(nsHttpAtom
          method == nsHttp::Report ||
          method == nsHttp::Search ||
          method == nsHttp::Trace;
 }
 
 nsresult
 HttpBaseChannel::SetupReplacementChannel(nsIURI       *newURI, 
                                          nsIChannel   *newChannel,
-                                         bool          preserveMethod,
-                                         bool          forProxy)
+                                         bool          preserveMethod)
 {
   LOG(("HttpBaseChannel::SetupReplacementChannel "
-     "[this=%p newChannel=%p preserveMethod=%d forProxy=%d]",
-     this, newChannel, preserveMethod, forProxy));
+     "[this=%p newChannel=%p preserveMethod=%d]",
+     this, newChannel, preserveMethod));
   PRUint32 newLoadFlags = mLoadFlags | LOAD_REPLACE;
   // if the original channel was using SSL and this channel is not using
   // SSL, then no need to inhibit persistent caching.  however, if the
   // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
   // set, then allow the flag to apply to the redirected channel as well.
   // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
   // we only need to check if the original channel was using SSL.
   if (mConnectionInfo->UsingSSL())
@@ -1645,31 +1644,16 @@ HttpBaseChannel::SetupReplacementChannel
   if (bag)
     mPropertyHash.EnumerateRead(CopyProperties, bag.get());
 
   // transfer timed channel enabled status
   nsCOMPtr<nsITimedChannel> timed(do_QueryInterface(newChannel));
   if (timed)
     timed->SetTimingEnabled(mTimingEnabled);
 
-  if (forProxy) {
-    // Transfer all the headers from the previous channel
-    //  this is needed for any headers that are not covered by the code above
-    //  or have been set separately. e.g. manually setting Referer without
-    //  setting up mReferrer
-    PRUint32 count = mRequestHead.Headers().Count();
-    for (PRUint32 i = 0; i < count; ++i) {
-      nsHttpAtom header;
-      const char *value = mRequestHead.Headers().PeekHeaderAt(i, header);
-
-      httpChannel->SetRequestHeader(nsDependentCString(header),
-                                    nsDependentCString(value), false);
-    }
-  }
-
   return NS_OK;
 }
 
 //------------------------------------------------------------------------------
 
 }  // namespace net
 }  // namespace mozilla
 
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -192,18 +192,17 @@ protected:
   void     DoNotifyListener();
   virtual void DoNotifyListenerCleanup() = 0;
 
   nsresult ApplyContentConversions();
 
   void AddCookiesToRequest();
   virtual nsresult SetupReplacementChannel(nsIURI *,
                                            nsIChannel *,
-                                           bool preserveMethod,
-                                           bool forProxy);
+                                           bool preserveMethod);
 
   // Helper function to simplify getting notification callbacks.
   template <class T>
   void GetCallback(nsCOMPtr<T> &aResult)
   {
     NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
                                   NS_GET_TEMPLATE_IID(T),
                                   getter_AddRefs(aResult));
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -717,17 +717,17 @@ HttpChannelChild::Redirect1Begin(const P
 
   // We won't get OnStartRequest, set cookies here.
   mResponseHead = new nsHttpResponseHead(responseHead);
   SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
 
   bool rewriteToGET = ShouldRewriteRedirectToGET(mResponseHead->Status(), 
                                                  mRequestHead.Method());
   
-  rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET, false);
+  rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET);
   if (NS_FAILED(rv)) {
     // Veto redirect.  nsHttpChannel decides to cancel or continue.
     OnRedirectVerifyCallback(rv);
     return;
   }
 
   mRedirectChannelChild = do_QueryInterface(newChannel);
   if (mRedirectChannelChild) {
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -1630,17 +1630,17 @@ nsHttpChannel::AsyncRedirectChannelToHtt
 
     nsCOMPtr<nsIIOService> ioService;
     rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = ioService->NewChannelFromURI(upgradedURI, getter_AddRefs(newChannel));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = SetupReplacementChannel(upgradedURI, newChannel, true, false);
+    rv = SetupReplacementChannel(upgradedURI, newChannel, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Inform consumers about this fake redirect
     mRedirectChannel = newChannel;
     PRUint32 flags = nsIChannelEventSink::REDIRECT_PERMANENT;
 
     PushRedirectAsyncFunc(
         &nsHttpChannel::ContinueAsyncRedirectChannelToHttps);
@@ -1727,17 +1727,17 @@ nsHttpChannel::AsyncDoReplaceWithProxy(n
     LOG(("nsHttpChannel::AsyncDoReplaceWithProxy [this=%p pi=%p]", this, pi));
     nsresult rv;
 
     nsCOMPtr<nsIChannel> newChannel;
     rv = gHttpHandler->NewProxiedChannel(mURI, pi, getter_AddRefs(newChannel));
     if (NS_FAILED(rv))
         return rv;
 
-    rv = SetupReplacementChannel(mURI, newChannel, true, true);
+    rv = SetupReplacementChannel(mURI, newChannel, true);
     if (NS_FAILED(rv))
         return rv;
 
     // Inform consumers about this fake redirect
     mRedirectChannel = newChannel;
     PRUint32 flags = nsIChannelEventSink::REDIRECT_INTERNAL;
 
     PushRedirectAsyncFunc(&nsHttpChannel::ContinueDoReplaceWithProxy);
@@ -2275,17 +2275,17 @@ nsHttpChannel::ProcessFallback(bool *wai
     // Close the current cache entry.
     CloseCacheEntry(true);
 
     // Create a new channel to load the fallback entry.
     nsRefPtr<nsIChannel> newChannel;
     rv = gHttpHandler->NewChannel(mURI, getter_AddRefs(newChannel));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = SetupReplacementChannel(mURI, newChannel, true, false);
+    rv = SetupReplacementChannel(mURI, newChannel, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Make sure the new channel loads from the fallback key.
     nsCOMPtr<nsIHttpChannelInternal> httpInternal =
         do_QueryInterface(newChannel, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = httpInternal->SetupFallbackChannel(mFallbackKey.get());
@@ -3948,25 +3948,23 @@ nsHttpChannel::ClearBogusContentEncoding
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel <redirect>
 //-----------------------------------------------------------------------------
 
 nsresult
 nsHttpChannel::SetupReplacementChannel(nsIURI       *newURI, 
                                        nsIChannel   *newChannel,
-                                       bool          preserveMethod,
-                                       bool          forProxy)
+                                       bool          preserveMethod)
 {
     LOG(("nsHttpChannel::SetupReplacementChannel "
          "[this=%p newChannel=%p preserveMethod=%d]",
          this, newChannel, preserveMethod));
 
-    nsresult rv = HttpBaseChannel::SetupReplacementChannel(newURI, newChannel,
-                                                           preserveMethod, forProxy);
+    nsresult rv = HttpBaseChannel::SetupReplacementChannel(newURI, newChannel, preserveMethod);
     if (NS_FAILED(rv))
         return rv;
 
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
     if (!httpChannel)
         return NS_OK; // no other options to set
 
     // convey the mApplyConversion flag (bug 91862)
@@ -3979,38 +3977,16 @@ nsHttpChannel::SetupReplacementChannel(n
         nsCOMPtr<nsIResumableChannel> resumableChannel(do_QueryInterface(newChannel));
         if (!resumableChannel) {
             NS_WARNING("Got asked to resume, but redirected to non-resumable channel!");
             return NS_ERROR_NOT_RESUMABLE;
         }
         resumableChannel->ResumeAt(mStartPos, mEntityID);
     }
 
-    if (forProxy) {
-        // Transfer the cache info to the new channel, if needed.
-        nsCOMPtr<nsICachingChannel> cachingChannel = do_QueryInterface(newChannel);
-        if (cachingChannel) {
-            // cacheKey is just mPostID wrapped in an nsISupportsPRUint32,
-            // we don't need to transfer it if it's 0.
-            if (mPostID) {
-                nsCOMPtr<nsISupports> cacheKey;
-                GetCacheKey(getter_AddRefs(cacheKey));
-                if (cacheKey) {
-                    cachingChannel->SetCacheKey(cacheKey);
-                }
-            }
-        }
-
-        nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel = do_QueryInterface(newChannel);
-        if (appCacheChannel) {
-            // app cache for write
-            appCacheChannel->SetApplicationCacheForWrite(mApplicationCacheForWrite);
-        }
-    }
-
     return NS_OK;
 }
 
 nsresult
 nsHttpChannel::AsyncProcessRedirection(PRUint32 redirectType)
 {
     LOG(("nsHttpChannel::AsyncProcessRedirection [this=%p type=%u]\n",
         this, redirectType));
@@ -4124,17 +4100,17 @@ nsHttpChannel::ContinueProcessRedirectio
     nsCOMPtr<nsIIOService> ioService;
     rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
     if (NS_FAILED(rv)) return rv;
 
     nsCOMPtr<nsIChannel> newChannel;
     rv = ioService->NewChannelFromURI(mRedirectURI, getter_AddRefs(newChannel));
     if (NS_FAILED(rv)) return rv;
 
-    rv = SetupReplacementChannel(mRedirectURI, newChannel, !rewriteToGET, false);
+    rv = SetupReplacementChannel(mRedirectURI, newChannel, !rewriteToGET);
     if (NS_FAILED(rv)) return rv;
 
     PRUint32 redirectFlags;
     if (mRedirectType == 301) // Moved Permanently
         redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
     else
         redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
 
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -175,19 +175,17 @@ private:
 
     // redirection specific methods
     void     HandleAsyncRedirect();
     nsresult ContinueHandleAsyncRedirect(nsresult);
     void     HandleAsyncNotModified();
     void     HandleAsyncFallback();
     nsresult ContinueHandleAsyncFallback(nsresult);
     nsresult PromptTempRedirect();
-    virtual nsresult SetupReplacementChannel(nsIURI *, nsIChannel *,
-                                             bool preserveMethod,
-                                             bool forProxy);
+    virtual nsresult SetupReplacementChannel(nsIURI *, nsIChannel *, bool preserveMethod);
 
     // proxy specific methods
     nsresult ProxyFailover();
     nsresult AsyncDoReplaceWithProxy(nsIProxyInfo *);
     nsresult ContinueDoReplaceWithProxy(nsresult);
     void HandleAsyncReplaceWithProxy();
     nsresult ContinueHandleAsyncReplaceWithProxy(nsresult);
     nsresult ResolveProxy();
deleted file mode 100644
--- a/netwerk/test/unit/test_proxy_preservation_bug235853.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* 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/. */
-
-do_load_httpd_js();
-
-var ios = Components.classes["@mozilla.org/network/io-service;1"]
-                    .getService(Components.interfaces.nsIIOService);
-
-var prefs = Components.classes["@mozilla.org/preferences-service;1"]
-                    .getService(Components.interfaces.nsIPrefBranch);
-
-function make_channel(url) {
-  return ios.newChannel(url, null, null)
-                .QueryInterface(Components.interfaces.nsIHttpChannel);
-}
-
-var httpserv = null;
-
-// respond with the value of the header
-function responseHandler(request, response) {
-  response.setHeader("Content-Type", "text/plain", false);
-
-  var value = request.hasHeader("SomeHeader") ? request.getHeader("SomeHeader") : "";
-  response.write("SomeHeader: " + value);
-}
-
-function run_test() {
-  httpserv = new nsHttpServer();
-  httpserv.start(4444);
-  httpserv.registerPathHandler("/test", responseHandler);
-  // setup an identity so we can use the server with a different name when using
-  // the server as a proxy
-  httpserv.identity.add("http", "foo", 80);
-
-  // cache key on channel creation
-  var orig_key;
-
-  // setup the properties that we want to be preserved
-  function setup_channel(chan) {
-    chan.setRequestHeader("SomeHeader", "Someval", false);
-
-    // set cache key to something other than 0
-    orig_key = chan.QueryInterface(Ci.nsICachingChannel)
-                      .cacheKey.QueryInterface(Ci.nsISupportsPRUint32);
-    orig_key.data = 0x32;
-    chan.QueryInterface(Ci.nsICachingChannel).cacheKey = orig_key;
-  }
-
-  // check that these properties are preserved
-  function check_response(request, data) {
-    // check that headers are preserved
-    do_check_eq(data, "SomeHeader: Someval");
-
-    // check that the cacheKey is preserved
-    var key = request.QueryInterface(Ci.nsICachingChannel)
-                        .cacheKey.QueryInterface(Ci.nsISupportsPRUint32);
-    do_check_eq(key.data, orig_key.data);
-  }
-
-  function setup_noproxy() {
-    var chan = make_channel("http://localhost:4444/test");
-    setup_channel(chan);
-    chan.asyncOpen(new ChannelListener(test_noproxy, null), null);
-  }
-
-  function test_noproxy(request, data, ctx) {
-    check_response(request, data);
-
-    setup_with_proxy();
-  }
-
-  function setup_with_proxy() {
-    // Setup a PAC rule using the server we setup as the proxy
-    var pac = 'data:text/plain,' +
-      'function FindProxyForURL(url, host) {' +
-      '  return "PROXY localhost:4444";' +
-      '}';
-
-    // Configure PAC
-    prefs.setIntPref("network.proxy.type", 2);
-    prefs.setCharPref("network.proxy.autoconfig_url", pac);
-
-    var chan = make_channel("http://foo/test");
-
-    setup_channel(chan);
-
-    chan.asyncOpen(new ChannelListener(test_with_proxy, null), null);
-  }
-
-  function test_with_proxy(request, data, ctx) {
-    check_response(request, data);
-
-    // cleanup PAC
-    prefs.setCharPref("network.proxy.autoconfig_url", "");
-    prefs.setIntPref("network.proxy.type", 0);
-
-    httpserv.stop(do_test_finished);
-  }
-
-  setup_noproxy();
-
-  do_test_pending();
-}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -153,17 +153,16 @@ skip-if = os == "win"
 [test_parse_content_type.js]
 [test_permmgr.js]
 [test_plaintext_sniff.js]
 [test_post.js]
 [test_progress.js]
 [test_protocolproxyservice.js]
 [test_proxy-failover_canceled.js]
 [test_proxy-failover_passing.js]
-[test_proxy_preservation_bug235853.js]
 [test_proxy-replace_canceled.js]
 [test_proxy-replace_passing.js]
 [test_range_requests.js]
 [test_readline.js]
 [test_redirect-caching_canceled.js]
 [test_redirect-caching_failure.js]
 [test_redirect-caching_passing.js]
 [test_redirect_canceled.js]
new file mode 100644
--- /dev/null
+++ b/python/README
@@ -0,0 +1,14 @@
+This directory contains common Python code.
+
+The basic rule is that if Python code is cross-module (that's "module" in the
+Mozilla meaning - as in "module ownership") and is MPL-compatible, it should
+go here.
+
+What should not go here:
+
+* Python that is not MPL-compatible (see other-licenses/)
+* Python that has good reason to remain close to its "owning" (Mozilla)
+  module (e.g. it is only being consumed from there).
+
+Historical information can be found at
+https://bugzilla.mozilla.org/show_bug.cgi?id=775243
rename from build/pylib/blessings/LICENSE
rename to python/blessings/LICENSE
rename from build/pylib/blessings/MANIFEST.in
rename to python/blessings/MANIFEST.in
rename from build/pylib/blessings/PKG-INFO
rename to python/blessings/PKG-INFO
rename from build/pylib/blessings/README.rst
rename to python/blessings/README.rst
rename from build/pylib/blessings/blessings/__init__.py
rename to python/blessings/blessings/__init__.py
rename from build/pylib/blessings/blessings/tests.py
rename to python/blessings/blessings/tests.py
rename from build/pylib/blessings/setup.cfg
rename to python/blessings/setup.cfg
rename from build/pylib/blessings/setup.py
rename to python/blessings/setup.py
rename from build/pylib/blessings/tox.ini
rename to python/blessings/tox.ini
deleted file mode 100644
deleted file mode 100644
deleted file mode 100644
--- a/services/common/storageserver.js
+++ b/services/common/storageserver.js
@@ -127,26 +127,38 @@ ServerBSO.prototype = {
     let body;
 
     function sendResponse() {
       response.setStatusLine(request.httpVersion, code, status);
       writeHttpBody(response, body);
     }
 
     if (request.hasHeader("x-if-modified-since")) {
-      let headerModified = parseInt(request.getHeader("x-if-modified-since"));
+      let headerModified = parseInt(request.getHeader("x-if-modified-since"),
+                                    10);
       CommonUtils.ensureMillisecondsTimestamp(headerModified);
 
       if (headerModified >= this.modified) {
         code = 304;
         status = "Not Modified";
 
         sendResponse();
         return;
       }
+    } else if (request.hasHeader("x-if-unmodified-since")) {
+      let requestModified = parseInt(request.getHeader("x-if-unmodified-since"),
+                                     10);
+      let serverModified = this.modified;
+
+      if (serverModified > requestModified) {
+        code = 412;
+        status = "Precondition Failed";
+        sendResponse();
+        return;
+      }
     }
 
     if (!this.deleted) {
       body = JSON.stringify(this.toJSON());
       response.setHeader("Content-Type", "application/json", false);
       response.setHeader("X-Last-Modified", "" + this.modified, false);
     } else {
       code = 404;
@@ -406,36 +418,16 @@ StorageServerCollection.prototype = {
     }
 
     if (options.older) {
       if (bso.modified >= options.older) {
         return false;
       }
     }
 
-    if (options.index_above) {
-      if (bso.sortindex === undefined) {
-        return false;
-      }
-
-      if (bso.sortindex <= options.index_above) {
-        return false;
-      }
-    }
-
-    if (options.index_below) {
-      if (bso.sortindex === undefined) {
-        return false;
-      }
-
-      if (bso.sortindex >= options.index_below) {
-        return false;
-      }
-    }
-
     return true;
   },
 
   count: function count(options) {
     options = options || {};
     let c = 0;
     for (let [id, bso] in Iterator(this._bsos)) {
       if (bso.modified && this._inResultSet(bso, options)) {
@@ -607,20 +599,21 @@ StorageServerCollection.prototype = {
   parseOptions: function parseOptions(request) {
     let options = {};
 
     for each (let chunk in request.queryString.split("&")) {
       if (!chunk) {
         continue;
       }
       chunk = chunk.split("=");
+      let key = decodeURIComponent(chunk[0]);
       if (chunk.length == 1) {
-        options[chunk[0]] = "";
+        options[key] = "";
       } else {
-        options[chunk[0]] = chunk[1];
+        options[key] = decodeURIComponent(chunk[1]);
       }
     }
 
     if (options.ids) {
       options.ids = options.ids.split(",");
     }
 
     if (options.newer) {
@@ -636,28 +629,16 @@ StorageServerCollection.prototype = {
       if (!isInteger(options.older)) {
         throw HTTP_400;
       }
 
       CommonUtils.ensureMillisecondsTimestamp(options.older);
       options.older = parseInt(options.older, 10);
     }
 
-    if (options.index_above) {
-      if (!isInteger(options.index_above)) {
-        throw HTTP_400;
-      }
-    }
-
-    if (options.index_below) {
-      if (!isInteger(options.index_below)) {
-        throw HTTP_400;
-      }
-    }
-
     if (options.limit) {
       if (!isInteger(options.limit)) {
         throw HTTP_400;
       }
 
       options.limit = parseInt(options.limit, 10);
     }
 
@@ -678,16 +659,26 @@ StorageServerCollection.prototype = {
         }
       }
 
       if (requestModified >= newestBSO) {
         response.setHeader("X-Last-Modified", "" + newestBSO);
         response.setStatusLine(request.httpVersion, 304, "Not Modified");
         return;
       }
+    } else if (request.hasHeader("x-if-unmodified-since")) {
+      let requestModified = parseInt(request.getHeader("x-if-unmodified-since"),
+                                     10);
+      let serverModified = this.timestamp;
+
+      if (serverModified > requestModified) {
+        response.setHeader("X-Last-Modified", "" + serverModified);
+        response.setStatusLine(request.httpVersion, 412, "Precondition Failed");
+        return;
+      }
     }
 
     if (options.full) {
       data = data.map(function map(bso) {
         return bso.toJSON();
       });
     } else {
       data = data.map(function map(bso) {
@@ -705,19 +696,17 @@ StorageServerCollection.prototype = {
         throw HTTP_406;
       }
     }
 
     let body;
     if (newlines) {
       response.setHeader("Content-Type", "application/newlines", false);
       let normalized = data.map(function map(d) {
-        let result = JSON.stringify(d);
-
-        return result.replace("\n", "\\u000a");
+        return JSON.stringify(d);
       });
 
       body = normalized.join("\n") + "\n";
     } else {
       response.setHeader("Content-Type", "application/json", false);
       body = JSON.stringify({items: data});
     }
 
@@ -750,20 +739,19 @@ StorageServerCollection.prototype = {
       }
 
       if (!Array.isArray(input)) {
         this._log.info("Input JSON type not an array!");
         return sendMozSvcError(request, response, "8");
       }
     } else if (inputMediaType == "application/newlines") {
       for each (let line in inputBody.split("\n")) {
-        let json = line.replace("\\u000a", "\n");
         let record;
         try {
-          record = JSON.parse(json);
+          record = JSON.parse(line);
         } catch (ex) {
           this._log.info("JSON parse error on line!");
           return sendMozSvcError(request, response, "8");
         }
 
         input.push(record);
       }
     } else {
--- a/services/common/storageservice.js
+++ b/services/common/storageservice.js
@@ -865,19 +865,22 @@ StorageServiceRequest.prototype = {
         this._log.error("415 HTTP response seen from server! This should " +
                         "never happen!");
         this._error = new StorageServiceRequestError();
         this._error.client = new Error("415 Unsupported Media Type received!");
         callOnComplete();
         return;
       }
 
-      if (response.status == 503) {
+      if (response.status >= 500 && response.status <= 599) {
+        this._log.error(response.status + " seen from server!");
         this._error = new StorageServiceRequestError();
-        this._error.server = new Error("503 Received.");
+        this._error.server = new Error(response.status + " status code.");
+        callOnComplete();
+        return;
       }
 
       callOnComplete();
 
     } catch (ex) {
       this._clientError = ex;
       this._log.info("Exception when processing _onComplete: " + ex);
 
@@ -989,30 +992,16 @@ StorageCollectionGetRequest.prototype = 
     if (value) {
       this._namedArgs.full = "1";
     } else {
       delete this._namedArgs["full"];
     }
   },
 
   /**
-   * Only retrieve BSOs whose sortindex is higher than this integer value.
-   */
-  set index_above(value) {
-    this._namedArgs.index_above = value;
-  },
-
-  /**
-   * Only retrieve BSOs whose sortindex is lower than this integer value.
-   */
-  set index_below(value) {
-    this._namedArgs.index_below = value;
-  },
-
-  /**
    * Limit the max number of returned BSOs to this integer number.
    */
   set limit(value) {
     this._namedArgs.limit = value;
   },
 
   /**
    * If set with any value, sort the results based on modification time, oldest
@@ -1079,25 +1068,31 @@ StorageCollectionGetRequest.prototype = 
 /**
  * Represents a request that sets data in a collection
  *
  * Instances of this type are returned by StorageServiceClient.setBSOs().
  */
 function StorageCollectionSetRequest() {
   StorageServiceRequest.call(this);
 
-  this._lines = [];
-  this._size  = 0;
+  this.size = 0;
 
-  this.successfulIDs = new Set();
-  this.failures      = new Map();
+  // TODO Bug 775781 convert to Set and Map once iterable.
+  this.successfulIDs = [];
+  this.failures      = {};
+
+  this._lines = [];
 }
 StorageCollectionSetRequest.prototype = {
   __proto__: StorageServiceRequest.prototype,
 
+  get count() {
+    return this._lines.length;
+  },
+
   /**
    * Add a BasicStorageObject to this request.
    *
    * Please note that the BSO content is retrieved when the BSO is added to
    * the request. If the BSO changes after it is added to a request, those
    * changes will not be reflected in the request.
    *
    * @param bso
@@ -1107,44 +1102,395 @@ StorageCollectionSetRequest.prototype = 
     if (!bso instanceof BasicStorageObject) {
       throw new Error("argument must be a BasicStorageObject instance.");
     }
 
     if (!bso.id) {
       throw new Error("Passed BSO must have id defined.");
     }
 
-    let line = JSON.stringify(bso).replace("\n", "\u000a");
+    this.addLine(JSON.stringify(bso));
+  },
 
+  /**
+   * Add a BSO (represented by its serialized newline-delimited form).
+   *
+   * You probably shouldn't use this. It is used for batching.
+   */
+  addLine: function addLine(line) {
     // This is off by 1 in the larger direction. We don't care.
-    this._size += line.length + "\n".length;
+    this.size += line.length + 1;
     this._lines.push(line);
   },
 
   _onDispatch: function _onDispatch() {
     this._data = this._lines.join("\n");
+    this.size = this._data.length;
   },
 
   _completeParser: function _completeParser(response) {
     let result = JSON.parse(response.body);
 
     for (let id of result.success) {
-      this.successfulIDs.add(id);
+      this.successfulIDs.push(id);
     }
 
     this.allSucceeded = true;
 
-    for (let [id, reasons] in result.failed) {
+    for (let [id, reasons] in Iterator(result.failed)) {
       this.failures[id] = reasons;
       this.allSucceeded = false;
     }
   },
 };
 
 /**
+ * Represents a batch upload of BSOs to an individual collection.
+ *
+ * This is a more intelligent way to upload may BSOs to the server. It will
+ * split the uploaded data into multiple requests so size limits, etc aren't
+ * exceeded.
+ *
+ * Once a client obtains an instance of this type, it calls `addBSO` for each
+ * BSO to be uploaded. When the client is done providing BSOs to be uploaded,
+ * it calls `finish`. When `finish` is called, no more BSOs can be added to the
+ * batch. When all requests created from this batch have finished, the callback
+ * provided to `finish` will be invoked.
+ *
+ * Clients can also explicitly flush pending outgoing BSOs via `flush`. This
+ * allows callers to control their own batching/chunking.
+ *
+ * Interally, this maintains a queue of StorageCollectionSetRequest to be
+ * issued. At most one request is allowed to be in-flight at once. This is to
+ * avoid potential conflicts on the server. And, in the case of conditional
+ * requests, it prevents requests from being declined due to the server being
+ * updated by another request issued by us.
+ *
+ * If a request errors for any reason, all queued uploads are abandoned and the
+ * `finish` callback is invoked as soon as possible. The `successfulIDs` and
+ * `failures` properties will contain data from all requests that had this
+ * response data. In other words, the IDs have BSOs that were never sent to the
+ * server are not lumped in to either property.
+ *
+ * Requests can be made conditional by setting `locallyModifiedVersion` to the
+ * most recent version of server data. As responses from the server are seen,
+ * the last server version is carried forward to subsequent requests.
+ *
+ * The server version from the last request is available in the
+ * `serverModifiedVersion` property. It should only be accessed during or
+ * after the callback passed to `finish`.
+ *
+ * @param client
+ *        (StorageServiceClient) Client instance to use for uploading.
+ *
+ * @param collection
+ *        (string) Collection the batch operation will upload to.
+ */
+function StorageCollectionBatchedSet(client, collection) {
+  this.client     = client;
+  this.collection = collection;
+
+  this._log = client._log;
+
+  this.locallyModifiedVersion = null;
+  this.serverModifiedVersion  = null;
+
+  // TODO Bug 775781 convert to Set and Map once iterable.
+  this.successfulIDs = [];
+  this.failures      = {};
+
+  // Request currently being populated.
+  this._stagingRequest = client.setBSOs(this.collection);
+
+  // Requests ready to be sent over the wire.
+  this._outgoingRequests = [];
+
+  // Whether we are waiting for a response.
+  this._requestInFlight = false;
+
+  this._onFinishCallback = null;
+  this._finished         = false;
+  this._errorEncountered = false;
+}
+StorageCollectionBatchedSet.prototype = {
+  /**
+   * Add a BSO to be uploaded as part of this batch.
+   */
+  addBSO: function addBSO(bso) {
+    if (this._errorEncountered) {
+      return;
+    }
+
+    let line = JSON.stringify(bso);
+
+    if (line.length > this.client.REQUEST_SIZE_LIMIT) {
+      throw new Error("BSO is larger than allowed limit: " + line.length +
+                      " > " + this.client.REQUEST_SIZE_LIMIT);
+    }
+
+    if (this._stagingRequest.size + line.length > this.client.REQUEST_SIZE_LIMIT) {
+      this._log.debug("Sending request because payload size would be exceeded");
+      this._finishStagedRequest();
+
+      this._stagingRequest.addLine(line);
+      return;
+    }
+
+    // We are guaranteed to fit within size limits.
+    this._stagingRequest.addLine(line);
+
+    if (this._stagingRequest.count >= this.client.REQUEST_BSO_COUNT_LIMIT) {
+      this._log.debug("Sending request because BSO count threshold reached.");
+      this._finishStagedRequest();
+      return;
+    }
+  },
+
+  finish: function finish(cb) {
+    if (this._finished) {
+      throw new Error("Batch request has already been finished.");
+    }
+
+    this.flush();
+
+    this._onFinishCallback = cb;
+    this._finished = true;
+    this._stagingRequest = null;
+  },
+
+  flush: function flush() {
+    if (this._finished) {
+      throw new Error("Batch request has been finished.");
+    }
+
+    if (!this._stagingRequest.count) {
+      return;
+    }
+
+    this._finishStagedRequest();
+  },
+
+  _finishStagedRequest: function _finishStagedRequest() {
+    this._outgoingRequests.push(this._stagingRequest);
+    this._sendOutgoingRequest();
+    this._stagingRequest = this.client.setBSOs(this.collection);
+  },
+
+  _sendOutgoingRequest: function _sendOutgoingRequest() {
+    if (this._requestInFlight || this._errorEncountered) {
+      return;
+    }
+
+    if (!this._outgoingRequests.length) {
+      return;
+    }
+
+    let request = this._outgoingRequests.shift();
+
+    if (this.locallyModifiedVersion) {
+      request.locallyModifiedVersion = this.locallyModifiedVersion;
+    }
+
+    request.dispatch(this._onBatchComplete.bind(this));
+    this._requestInFlight = true;
+  },
+
+  _onBatchComplete: function _onBatchComplete(error, request) {
+    this._requestInFlight = false;
+
+    this.serverModifiedVersion = request.serverTime;
+
+    // Only update if we had a value before. Otherwise, this breaks
+    // unconditional requests!
+    if (this.locallyModifiedVersion) {
+      this.locallyModifiedVersion = request.serverTime;
+    }
+
+    for (let id of request.successfulIDs) {
+      this.successfulIDs.push(id);
+    }
+
+    for (let [id, reason] in Iterator(request.failures)) {
+      this.failures[id] = reason;
+    }
+
+    if (request.error) {
+      this._errorEncountered = true;
+    }
+
+    this._checkFinish();
+  },
+
+  _checkFinish: function _checkFinish() {
+    if (this._outgoingRequests.length && !this._errorEncountered) {
+      this._sendOutgoingRequest();
+      return;
+    }
+
+    if (!this._onFinishCallback) {
+      return;
+    }
+
+    try {
+      this._onFinishCallback(this);
+    } catch (ex) {
+      this._log.warn("Exception when calling finished callback: " +
+                     CommonUtils.exceptionStr(ex));
+    }
+  },
+};
+Object.freeze(StorageCollectionBatchedSet.prototype);
+
+/**
+ * Manages a batch of BSO deletion requests.
+ *
+ * A single instance of this virtual request allows deletion of many individual
+ * BSOs without having to worry about server limits.
+ *
+ * Instances are obtained by calling `deleteBSOsBatching` on
+ * StorageServiceClient.
+ *
+ * Usage is roughly the same as StorageCollectionBatchedSet. Callers obtain
+ * an instance and select individual BSOs for deletion by calling `addID`.
+ * When the caller is finished marking BSOs for deletion, they call `finish`
+ * with a callback which will be invoked when all deletion requests finish.
+ *
+ * When the finished callback is invoked, any encountered errors will be stored
+ * in the `errors` property of this instance (which is passed to the callback).
+ * This will be an empty array if no errors were encountered. Else, it will
+ * contain the errors from the `onComplete` handler of request instances. The
+ * set of succeeded and failed IDs is not currently available.
+ *
+ * Deletes can be made conditional by setting `locallyModifiedVersion`. The
+ * behavior is the same as request types. The only difference is that the
+ * updated version from the server as a result of requests is carried forward
+ * to subsequent requests.
+ *
+ * The server version from the last request is stored in the
+ * `serverModifiedVersion` property. It is not safe to access this until the
+ * callback from `finish`.
+ *
+ * Like StorageCollectionBatchedSet, requests are issued serially to avoid
+ * race conditions on the server.
+ *
+ * @param client
+ *        (StorageServiceClient) Client request is associated with.
+ * @param collection
+ *        (string) Collection being operated on.
+ */
+function StorageCollectionBatchedDelete(client, collection) {
+  this.client     = client;
+  this.collection = collection;
+
+  this._log = client._log;
+
+  this.locallyModifiedVersion = null;
+  this.serverModifiedVersion  = null;
+  this.errors                 = [];
+
+  this._pendingIDs          = [];
+  this._requestInFlight     = false;
+  this._finished            = false;
+  this._finishedCallback    = null;
+}
+StorageCollectionBatchedDelete.prototype = {
+  addID: function addID(id) {
+    if (this._finished) {
+      throw new Error("Cannot add IDs to a finished instance.");
+    }
+
+    // If we saw errors already, don't do any work. This is an optimization
+    // and isn't strictly required, as _sendRequest() should no-op.
+    if (this.errors.length) {
+      return;
+    }
+
+    this._pendingIDs.push(id);
+
+    if (this._pendingIDs.length >= this.client.REQUEST_BSO_DELETE_LIMIT) {
+      this._sendRequest();
+    }
+  },
+
+  /**
+   * Finish this batch operation.
+   *
+   * No more IDs can be added to this operation. Existing IDs are flushed as
+   * a request. The passed callback will be called when all requests have
+   * finished.
+   */
+  finish: function finish(cb) {
+    if (this._finished) {
+      throw new Error("Batch delete instance has already been finished.");
+    }
+
+    this._finished = true;
+    this._finishedCallback = cb;
+
+    if (this._pendingIDs.length) {
+      this._sendRequest();
+    }
+  },
+
+  _sendRequest: function _sendRequest() {
+    // Only allow 1 active request at a time and don't send additional
+    // requests if one has failed.
+    if (this._requestInFlight || this.errors.length) {
+      return;
+    }
+
+    let ids = this._pendingIDs.splice(0, this.client.REQUEST_BSO_DELETE_LIMIT);
+    let request = this.client.deleteBSOs(this.collection, ids);
+
+    if (this.locallyModifiedVersion) {
+      request.locallyModifiedVersion = this.locallyModifiedVersion;
+    }
+
+    request.dispatch(this._onRequestComplete.bind(this));
+    this._requestInFlight = true;
+  },
+
+  _onRequestComplete: function _onRequestComplete(error, request) {
+    this._requestInFlight = false;
+
+    if (error) {
+      // We don't currently track metadata of what failed. This is an obvious
+      // feature that could be added.
+      this._log.warn("Error received from server: " + error);
+      this.errors.push(error);
+    }
+
+    this.serverModifiedVersion = request.serverTime;
+
+    // If performing conditional requests, carry forward the new server version
+    // so subsequent conditional requests work.
+    if (this.locallyModifiedVersion) {
+      this.locallyModifiedVersion = request.serverTime;
+    }
+
+    if (this._pendingIDs.length && !this.errors.length) {
+      this._sendRequest();
+      return;
+    }
+
+    if (!this._finishedCallback) {
+      return;
+    }
+
+    try {
+      this._finishedCallback(this);
+    } catch (ex) {
+      this._log.warn("Exception when invoking finished callback: " +
+                     CommonUtils.exceptionStr(ex));
+    }
+  },
+};
+Object.freeze(StorageCollectionBatchedDelete.prototype);
+
+/**
  * Construct a new client for the SyncStorage API, version 2.0.
  *
  * Clients are constructed against a base URI. This URI is typically obtained
  * from the token server via the endpoint component of a successful token
  * response.
  *
  * The purpose of this type is to serve as a middleware between a client's core
  * logic and the HTTP API. It hides the details of how the storage API is
@@ -1190,16 +1536,37 @@ function StorageServiceClient(baseURI) {
 StorageServiceClient.prototype = {
   /**
    * The user agent sent with every request.
    *
    * You probably want to change this.
    */
   userAgent: "StorageServiceClient",
 
+  /**
+   * Maximum size of entity bodies.
+   *
+   * TODO this should come from the server somehow. See bug 769759.
+   */
+  REQUEST_SIZE_LIMIT: 512000,
+
+  /**
+   * Maximum number of BSOs in requests.
+   *
+   * TODO this should come from the server somehow. See bug 769759.
+   */
+  REQUEST_BSO_COUNT_LIMIT: 100,
+
+  /**
+   * Maximum number of BSOs that can be deleted in a single DELETE.
+   *
+   * TODO this should come from the server. See bug 769759.
+   */
+  REQUEST_BSO_DELETE_LIMIT: 100,
+
   _baseURI: null,
   _log: null,
 
   _listeners: null,
 
   //----------------------------
   // Event Listener Management |
   //----------------------------
@@ -1579,21 +1946,19 @@ StorageServiceClient.prototype = {
    *
    * The request can be made conditional by setting `locallyModifiedVersion`
    * on the returned request instance.
    *
    * This function returns a StorageCollectionSetRequest instance. This type
    * has additional functions and properties specific to this operation. See
    * its documentation for more.
    *
-   * Future improvement: support streaming of uploaded records. Currently, data
-   * is buffered in the client before going over the wire. Ideally, we'd support
-   * sending over the wire as soon as data is available. This will require
-   * support in RESTRequest, which doesn't support streaming on requests, only
-   * responses.
+   * Most consumers interested in submitting multiple BSOs to the server will
+   * want to use `setBSOsBatching` instead. That API intelligently splits up
+   * requests as necessary, etc.
    *
    * Example usage:
    *
    *   let request = client.setBSOs("collection0");
    *   let bso0 = new BasicStorageObject("id0");
    *   bso0.payload = "payload0";
    *
    *   let bso1 = new BasicStorageObject("id1");
@@ -1631,16 +1996,40 @@ StorageServiceClient.prototype = {
       accept:            "application/json",
       allowIfUnmodified: true,
     });
 
     return request;
   },
 
   /**
+   * This is a batching variant of setBSOs.
+   *
+   * Whereas `setBSOs` is a 1:1 mapping between function calls and HTTP
+   * requests issued, this one is a 1:N mapping. It will intelligently break
+   * up outgoing BSOs into multiple requests so size limits, etc aren't
+   * exceeded.
+   *
+   * Please see the documentation for `StorageCollectionBatchedSet` for
+   * usage info.
+   *
+   * @param collection
+   *        (string) Collection to operate on.
+   * @return
+   *        (StorageCollectionBatchedSet) Batched set instance.
+   */
+  setBSOsBatching: function setBSOsBatching(collection) {
+    if (!collection) {
+      throw new Error("collection argument must be defined.");
+    }
+
+    return new StorageCollectionBatchedSet(this, collection);
+  },
+
+  /**
    * Deletes a single BSO from a collection.
    *
    * The request can be made conditional by setting `locallyModifiedVersion`
    * on the returned request instance.
    *
    * @param collection
    *        (string) Collection to operate on.
    * @param id
@@ -1665,16 +2054,20 @@ StorageServiceClient.prototype = {
    * Delete multiple BSOs from a specific collection.
    *
    * This is functional equivalent to calling deleteBSO() for every ID but
    * much more efficient because it only results in 1 round trip to the server.
    *
    * The request can be made conditional by setting `locallyModifiedVersion`
    * on the returned request instance.
    *
+   * If the number of BSOs to delete is potentially large, it is preferred to
+   * use `deleteBSOsBatching`. That API automatically splits the operation into
+   * multiple requests so server limits aren't exceeded.
+   *
    * @param collection
    *        (string) Name of collection to delete BSOs from.
    * @param ids
    *        (iterable of strings) Set of BSO IDs to delete.
    */
   deleteBSOs: function deleteBSOs(collection, ids) {
     // In theory we should URL encode. However, IDs are supposed to be URL
     // safe. If we get garbage in, we'll get garbage out and the server will
@@ -1684,16 +2077,34 @@ StorageServiceClient.prototype = {
     let uri = this._baseURI + "storage/" + collection + "?ids=" + s;
 
     return this._getRequest(uri, "DELETE", {
       allowIfUnmodified: true,
     });
   },
 
   /**
+   * Bulk deletion of BSOs with no size limit.
+   *
+   * This allows a large amount of BSOs to be deleted easily. It will formulate
+   * multiple `deleteBSOs` queries so the client does not exceed server limits.
+   *
+   * @param collection
+   *        (string) Name of collection to delete BSOs from.
+   * @return StorageCollectionBatchedDelete
+   */
+  deleteBSOsBatching: function deleteBSOsBatching(collection) {
+    if (!collection) {
+      throw new Error("collection argument must be defined.");
+    }
+
+    return new StorageCollectionBatchedDelete(this, collection);
+  },
+
+  /**
    * Deletes a single collection from the server.
    *
    * The request can be made conditional by setting `locallyModifiedVersion`
    * on the returned request instance.
    *
    * @param collection
    *        (string) Name of collection to delete.
    */
--- a/services/common/tests/unit/test_storage_server.js
+++ b/services/common/tests/unit/test_storage_server.js
@@ -248,16 +248,38 @@ add_test(function test_bso_get_existing(
   do_check_eq(bso.modified, coll.bso("bso").modified);
   let payload = JSON.parse(bso.payload);
   do_check_attribute_count(payload, 1);
   do_check_eq(payload.foo, "bar");
 
   server.stop(run_next_test);
 });
 
+add_test(function test_percent_decoding() {
+  _("Ensure query string arguments with percent encoded are handled.");
+
+  let server = new StorageServer();
+  server.registerUser("123", "password");
+  server.startSynchronous(PORT);
+
+  let coll = server.user("123").createCollection("test");
+  coll.insert("001", {foo: "bar"});
+  coll.insert("002", {bar: "foo"});
+
+  let request = localRequest("/2.0/123/storage/test?ids=001%2C002", "123",
+                             "password");
+  let error = doGetRequest(request);
+  do_check_null(error);
+  do_check_eq(request.response.status, 200);
+  let items = JSON.parse(request.response.body).items;
+  do_check_attribute_count(items, 2);
+
+  server.stop(run_next_test);
+});
+
 add_test(function test_bso_404() {
   _("Ensure the server responds with a 404 if a BSO does not exist.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.createContents("123", {
     test: {}
   });
@@ -437,16 +459,70 @@ add_test(function test_bso_delete_unmodi
   let error = doDeleteRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 204);
   do_check_true(coll.bso("myid").deleted);
 
   server.stop(run_next_test);
 });
 
+add_test(function test_collection_get_unmodified_since() {
+  _("Ensure conditional unmodified get on collection works when it should.");
+
+  let server = new StorageServer();
+  server.registerUser("123", "password");
+  server.startSynchronous(PORT);
+  let collection = server.user("123").createCollection("testcoll");
+  collection.insert("bso0", {foo: "bar"});
+
+  let serverModified = collection.timestamp;
+
+  let request1 = localRequest("/2.0/123/storage/testcoll", "123", "password");
+  request1.setHeader("X-If-Unmodified-Since", serverModified);
+  let error = doGetRequest(request1);
+  do_check_null(error);
+  do_check_eq(request1.response.status, 200);
+
+  let request2 = localRequest("/2.0/123/storage/testcoll", "123", "password");
+  request2.setHeader("X-If-Unmodified-Since", serverModified - 1);
+  let error = doGetRequest(request2);
+  do_check_null(error);
+  do_check_eq(request2.response.status, 412);
+
+  server.stop(run_next_test);
+});
+
+add_test(function test_bso_get_unmodified_since() {
+  _("Ensure conditional unmodified get on BSO works appropriately.");
+
+  let server = new StorageServer();
+  server.registerUser("123", "password");
+  server.startSynchronous(PORT);
+  let collection = server.user("123").createCollection("testcoll");
+  let bso = collection.insert("bso0", {foo: "bar"});
+
+  let serverModified = bso.modified;
+
+  let request1 = localRequest("/2.0/123/storage/testcoll/bso0", "123",
+                              "password");
+  request1.setHeader("X-If-Unmodified-Since", serverModified);
+  let error = doGetRequest(request1);
+  do_check_null(error);
+  do_check_eq(request1.response.status, 200);
+
+  let request2 = localRequest("/2.0/123/storage/testcoll/bso0", "123",
+                              "password");
+  request2.setHeader("X-If-Unmodified-Since", serverModified - 1);
+  let error = doGetRequest(request2);
+  do_check_null(error);
+  do_check_eq(request2.response.status, 412);
+
+  server.stop(run_next_test);
+});
+
 add_test(function test_missing_collection_404() {
   _("Ensure a missing collection returns a 404.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.startSynchronous(PORT);
 
   let request = localRequest("/2.0/123/storage/none", "123", "password");
--- a/services/common/tests/unit/test_storageservice_client.js
+++ b/services/common/tests/unit/test_storageservice_client.js
@@ -7,40 +7,44 @@ Cu.import("resource://testing-common/ser
 const BASE_URI = "http://localhost:8080/2.0";
 
 function run_test() {
   initTestLogging("Trace");
 
   run_next_test();
 }
 
-function getEmptyServer(user="765", password="password") {
+function getRandomUser() {
+  return "" + (Math.floor(Math.random() * 100000) + 1);
+}
+
+function getEmptyServer(user=getRandomUser(), password="password") {
   let users = {};
   users[user] = password;
 
   return storageServerForUsers(users, {
     meta:    {},
     clients: {},
     crypto:  {},
   });
 }
 
-function getClient(user="765", password="password") {
+function getClient(user=getRandomUser(), password="password") {
   let client = new StorageServiceClient(BASE_URI + "/" + user);
   client.addListener({
     onDispatch: function onDispatch(request) {
       let up = user + ":" + password;
       request.request.setHeader("authorization", "Basic " + btoa(up));
     }
   });
 
   return client;
 }
 
-function getServerAndClient(user="765", password="password") {
+function getServerAndClient(user=getRandomUser(), password="password") {
   let server = getEmptyServer(user, password);
   let client = getClient(user, password);
 
   return [server, client, user, password];
 }
 
 add_test(function test_auth_failure_listener() {
   _("Ensure the onAuthFailure listener is invoked.");
@@ -639,19 +643,19 @@ add_test(function test_set_bsos_simple()
   let request = client.setBSOs("testcollection");
   request.addBSO(bso0);
   request.addBSO(bso1);
 
   request.dispatch(function onComplete(error, req) {
     do_check_null(error);
 
     let successful = req.successfulIDs;
-    do_check_eq(successful.size(), 2);
-    do_check_true(successful.has(bso0.id));
-    do_check_true(successful.has(bso1.id));
+    do_check_eq(successful.length, 2);
+    do_check_eq(successful.indexOf(bso0.id), 0);
+    do_check_true(successful.indexOf(bso1.id), 1);
 
     server.stop(run_next_test);
   });
 });
 
 add_test(function test_set_bsos_invalid_bso() {
   _("Ensure that adding an invalid BSO throws.");
 
@@ -696,17 +700,17 @@ add_test(function test_set_bsos_newline(
   request.addBSO(bso0);
 
   let bso1 = new BasicStorageObject("bso1");
   bso1.payload = "foobar";
   request.addBSO(bso1);
 
   request.dispatch(function onComplete(error, request) {
     do_check_null(error);
-    do_check_eq(request.successfulIDs.size(), 2);
+    do_check_eq(request.successfulIDs.length, 2);
 
     let coll = user.collection("testcoll");
     do_check_eq(coll.bso("bso0").payload, bso0.payload);
     do_check_eq(coll.bso("bso1").payload, bso1.payload);
 
     server.stop(run_next_test);
   });
 });
@@ -960,8 +964,415 @@ add_test(function test_network_error_lis
     }
   });
   let request = client.getCollectionInfo();
   request.dispatch(function() {
     do_check_true(listenerCalled);
     run_next_test();
   });
 });
+
+add_test(function test_batching_set_too_large() {
+  _("Ensure we throw when attempting to add a BSO that is too large to fit.");
+
+  let [server, client, username] = getServerAndClient();
+
+  let request = client.setBSOsBatching("testcoll");
+  let payload = "";
+
+  // The actual length of the payload is a little less. But, this ensures we
+  // exceed it.
+  for (let i = 0; i < client.REQUEST_SIZE_LIMIT; i++) {
+    payload += i;
+  }
+
+  let bso = new BasicStorageObject("bso");
+  bso.payload = payload;
+  do_check_throws(function add() { request.addBSO(bso); });
+
+  server.stop(run_next_test);
+});
+
+add_test(function test_batching_set_basic() {
+  _("Ensure batching set works with single requests.");
+
+  let [server, client, username] = getServerAndClient();
+
+  let request = client.setBSOsBatching("testcoll");
+  for (let i = 0; i < 10; i++) {
+    let bso = new BasicStorageObject("bso" + i);
+    bso.payload = "payload" + i;
+    request.addBSO(bso);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(request.successfulIDs.length, 10);
+
+    let collection = server.user(username).collection("testcoll");
+    do_check_eq(collection.timestamp, request.serverModifiedVersion);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batching_set_batch_count() {
+  _("Ensure multiple outgoing request batching works when count is exceeded.");
+
+  let [server, client, username] = getServerAndClient();
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+  }
+
+  let request = client.setBSOsBatching("testcoll");
+  for (let i = 1; i <= 300; i++) {
+    let bso = new BasicStorageObject("bso" + i);
+    bso.payload = "XXXXXXX";
+    request.addBSO(bso);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(request.successfulIDs.length, 300);
+    do_check_eq(requestCount, 3);
+
+    let collection = server.user(username).collection("testcoll");
+    do_check_eq(collection.timestamp, request.serverModifiedVersion);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batching_set_batch_size() {
+  _("Ensure outgoing requests batch when size is exceeded.");
+
+  let [server, client, username] = getServerAndClient();
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+  };
+
+  let limit = client.REQUEST_SIZE_LIMIT;
+
+  let request = client.setBSOsBatching("testcoll");
+
+  // JavaScript: Y U NO EASY REPETITION FUNCTIONALITY?
+  let data = [];
+  for (let i = (limit / 2) - 100; i; i -= 1) {
+    data.push("X");
+  }
+
+  let payload = data.join("");
+
+  for (let i = 0; i < 4; i++) {
+    let bso = new BasicStorageObject("bso" + i);
+    bso.payload = payload;
+    request.addBSO(bso);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(request.successfulIDs.length, 4);
+    do_check_eq(requestCount, 2);
+
+    let collection = server.user(username).collection("testcoll");
+    do_check_eq(collection.timestamp, request.serverModifiedVersion);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batching_set_flush() {
+  _("Ensure flushing batch sets works.");
+
+  let [server, client, username] = getServerAndClient();
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+  }
+
+  let request = client.setBSOsBatching("testcoll");
+  for (let i = 1; i < 101; i++) {
+    let bso = new BasicStorageObject("bso" + i);
+    bso.payload = "foo";
+    request.addBSO(bso);
+
+    if (i % 10 == 0) {
+      request.flush();
+    }
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(request.successfulIDs.length, 100);
+    do_check_eq(requestCount, 10);
+
+    let collection = server.user(username).collection("testcoll");
+    do_check_eq(collection.timestamp, request.serverModifiedVersion);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batching_set_conditional_success() {
+  _("Ensure conditional requests for batched sets work properly.");
+
+  let [server, client, username] = getServerAndClient();
+
+  let collection = server.user(username).createCollection("testcoll");
+
+  let lastServerVersion = Date.now();
+  collection.insertBSO(new ServerBSO("foo", "bar", lastServerVersion));
+  collection.timestamp = lastServerVersion;
+  do_check_eq(collection.timestamp, lastServerVersion);
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+  }
+
+  let request = client.setBSOsBatching("testcoll");
+  request.locallyModifiedVersion = collection.timestamp;
+
+  for (let i = 1; i < 251; i++) {
+    let bso = new BasicStorageObject("bso" + i);
+    bso.payload = "foo" + i;
+    request.addBSO(bso);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 3);
+
+    do_check_eq(collection.timestamp, request.serverModifiedVersion);
+    do_check_eq(collection.timestamp, request.locallyModifiedVersion);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batching_set_initial_failure() {
+  _("Ensure that an initial request failure setting BSOs is handled properly.");
+
+  let [server, client, username] = getServerAndClient();
+
+  let collection = server.user(username).createCollection("testcoll");
+  collection.timestamp = Date.now();
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+  }
+
+  let request = client.setBSOsBatching("testcoll");
+  request.locallyModifiedVersion = collection.timestamp - 1;
+
+  for (let i = 1; i < 250; i++) {
+    let bso = new BasicStorageObject("bso" + i);
+    bso.payload = "foo" + i;
+    request.addBSO(bso);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 1);
+
+    do_check_eq(request.successfulIDs.length, 0);
+    do_check_eq(Object.keys(request.failures).length, 0);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batching_set_subsequent_failure() {
+  _("Ensure a non-initial failure during batching set is handled properly.");
+
+  let [server, client, username] = getServerAndClient();
+  let collection = server.user(username).createCollection("testcoll");
+  collection.timestamp = Date.now();
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+
+    if (requestCount == 1) {
+      return;
+    }
+
+    collection.timestamp++;
+  }
+
+  let request = client.setBSOsBatching("testcoll");
+  request.locallyModifiedVersion = collection.timestamp;
+
+  for (let i = 0; i < 250; i++) {
+    let bso = new BasicStorageObject("bso" + i);
+    bso.payload = "foo" + i;
+    request.addBSO(bso);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 2);
+    do_check_eq(request.successfulIDs.length, 100);
+    do_check_eq(Object.keys(request.failures).length, 0);
+
+    server.stop(run_next_test);
+  });
+});
+
+function getBatchedDeleteData(collection="testcoll") {
+  let [server, client, username] = getServerAndClient();
+
+  let serverBSOs = {};
+  for (let i = 1000; i; i -= 1) {
+    serverBSOs["bso" + i] = new ServerBSO("bso" + i, "payload" + i);
+  }
+
+  let user = server.user(username);
+  user.createCollection(collection, serverBSOs);
+
+  return [server, client, username, collection];
+}
+
+add_test(function test_batched_delete_single() {
+  _("Ensure batched delete with single request works.");
+
+  let [server, client, username, collection] = getBatchedDeleteData();
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount += 1;
+  }
+
+  let request = client.deleteBSOsBatching(collection);
+  for (let i = 1; i < 51; i += 1) {
+    request.addID("bso" + i);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 1);
+    do_check_eq(request.errors.length, 0);
+
+    let coll = server.user(username).collection(collection);
+    do_check_eq(coll.count(), 950);
+
+    do_check_eq(request.serverModifiedVersion, coll.timestamp);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batched_delete_multiple() {
+  _("Ensure batched delete splits requests properly.");
+
+  let [server, client, username, collection] = getBatchedDeleteData();
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount += 1;
+  }
+
+  let request = client.deleteBSOsBatching(collection);
+  for (let i = 1; i < 251; i += 1) {
+    request.addID("bso" + i);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 3);
+    do_check_eq(request.errors.length, 0);
+
+    let coll = server.user(username).collection(collection);
+    do_check_eq(coll.count(), 750);
+
+    do_check_eq(request.serverModifiedVersion, coll.timestamp);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batched_delete_conditional_success() {
+  _("Ensure conditional batched delete all work.");
+
+  let [server, client, username, collection] = getBatchedDeleteData();
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+  }
+
+  let serverCollection = server.user(username).collection(collection);
+  let initialTimestamp = serverCollection.timestamp;
+
+  let request = client.deleteBSOsBatching(collection);
+  request.locallyModifiedVersion = initialTimestamp;
+
+  for (let i = 1; i < 251; i += 1) {
+    request.addID("bso" + 1);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 3);
+    do_check_eq(request.errors.length, 0);
+
+    do_check_true(request.locallyModifiedVersion > initialTimestamp);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batched_delete_conditional_initial_failure() {
+  _("Ensure conditional batched delete failure on initial request works.");
+
+  // The client needs to issue multiple requests but the first one was
+  // rejected. The client should only issue that initial request.
+  let [server, client, username, collection] = getBatchedDeleteData();
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+  }
+
+  let serverCollection = server.user(username).collection(collection);
+  let request = client.deleteBSOsBatching(collection);
+  request.locallyModifiedVersion = serverCollection.timestamp - 1;
+
+  for (let i = 1; i < 251; i += 1) {
+    request.addID("bso" + i);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 1);
+    do_check_eq(request.errors.length, 1);
+
+    server.stop(run_next_test);
+  });
+});
+
+add_test(function test_batched_delete_conditional_subsequent_failure() {
+  _("Ensure conditional batched delete failure on non-initial request.");
+
+  let [server, client, username, collection] = getBatchedDeleteData();
+
+  let serverCollection = server.user(username).collection(collection);
+
+  let requestCount = 0;
+  server.callback.onRequest = function onRequest() {
+    requestCount++;
+
+    if (requestCount <= 1) {
+      return;
+    }
+
+    // Advance collection's timestamp on subsequent requests so request is
+    // rejected.
+    serverCollection.timestamp++;
+  }
+
+  let request = client.deleteBSOsBatching(collection);
+  request.locallyModifiedVersion = serverCollection.timestamp;
+
+  for (let i = 1; i < 251; i += 1) {
+    request.addID("bso" + i);
+  }
+
+  request.finish(function onFinish(request) {
+    do_check_eq(requestCount, 2);
+    do_check_eq(request.errors.length, 1);
+
+    server.stop(run_next_test);
+  });
+});
--- a/services/sync/tests/unit/test_resource_async.js
+++ b/services/sync/tests/unit/test_resource_async.js
@@ -658,36 +658,40 @@ add_test(function test_uri_construction(
   let uri2 = Utils.makeURI("http://foo/")
                   .QueryInterface(Ci.nsIURL);
   uri2.query = query;
   do_check_eq(uri1.query, uri2.query);
 
   run_next_test();
 });
 
+/**
+ * End of tests that rely on a single HTTP server.
+ * All tests after this point must begin and end their own.
+ */
+add_test(function eliminate_server() {
+  server.stop(run_next_test);
+});
+
 add_test(function test_new_channel() {
   _("Ensure a redirect to a new channel is handled properly.");
 
   let resourceRequested = false;
   function resourceHandler(metadata, response) {
     resourceRequested = true;
 
     let body = "Test";
     response.setHeader("Content-Type", "text/plain");
     response.bodyOutputStream.write(body, body.length);
   }
-  let server2 = httpd_setup({"/resource": resourceHandler}, 8081);
+  let server = httpd_setup({"/resource": resourceHandler}, 8080);
 
-  let request = new AsyncResource("http://localhost:8080/redirect");
+  let request = new AsyncResource("http://localhost:8080/resource");
   request.get(function onRequest(error, content) {
     do_check_null(error);
     do_check_true(resourceRequested);
     do_check_eq(200, content.status);
     do_check_true("content-type" in content.headers);
     do_check_eq("text/plain", content.headers["content-type"]);
 
-    server2.stop(run_next_test);
+    server.stop(run_next_test);
   });
 });
-
-add_test(function tear_down() {
-  server.stop(run_next_test);
-});
--- a/testing/mochitest/android.json
+++ b/testing/mochitest/android.json
@@ -124,17 +124,16 @@
  "dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html": "TIMED_OUT, bug 766586",
  "dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html": "TIMED_OUT, bug 766586",
  "dom/imptests/editing/conformancetest/test_event.html": "",
  "dom/imptests/editing/conformancetest/test_runtest.html": "",
  "dom/imptests/html/tests/submission/Mozilla/test_window-onerror-parse-error.html": "",
  "dom/imptests/html/tests/submission/Mozilla/test_window-onerror-runtime-error-throw.html": "",
  "dom/imptests/html/tests/submission/Mozilla/test_window-onerror-runtime-error.html": "",
  "dom/indexedDB/test/test_third_party.html": "TIMED_OUT",
- "dom/indexedDB/ipc/test_ipc.html": "bug 775982", 
  "dom/network/tests/test_network_basics.html": "",
  "dom/settings/tests/test_settings_events.html": "",
  "dom/settings/tests/test_settings_basics.html": "",
  "dom/contacts/tests/test_contacts_basics.html": "",
  "dom/contacts/tests/test_contacts_events.html": "",
  "dom/sms/tests/test_sms_basics.html": "",
  "dom/tests/mochitest/ajax/offline/test_simpleManifest.html": "TIMED_OUT",
  "dom/tests/mochitest/ajax/offline/test_updatingManifest.html": "TIMED_OUT",
@@ -151,17 +150,17 @@
  "dom/tests/mochitest/bugs/test_bug437361.html": "",
  "dom/tests/mochitest/bugs/test_bug479143.html": "",
  "dom/tests/mochitest/bugs/test_bug504862.html": "RANDOM",
  "dom/tests/mochitest/bugs/test_bug597809.html": "",
  "dom/tests/mochitest/bugs/test_bug61098.html": "",
  "dom/tests/mochitest/bugs/test_bug641552.html": "",
  "dom/tests/mochitest/bugs/test_resize_move_windows.html": "TIMED_OUT",
  "dom/tests/mochitest/bugs/test_window_bar.html": "",
- "dom/devicestorage/ipc/test_ipc.html": "bug 775053",
+ "dom/devicestorage/ipc/test_ipc.html": "",
  "dom/devicestorage/test/test_basic.html": "",
  "dom/devicestorage/test/test_dotdot.html": "",
  "dom/devicestorage/test/test_enumerate.html": "",
  "dom/devicestorage/test/test_enumerateMultipleContinue.html": "",
  "dom/devicestorage/test/test_enumerateOptions.html": "",
  "dom/devicestorage/test/test_lastModificationFilter.html": "",
  "dom/devicestorage/test/test_overwrite.html": "",
  "dom/devicestorage/test/test_sanity.html": "",
--- a/testing/peptest/peptest/extension/resource/mozmill/README.md
+++ b/testing/peptest/peptest/extension/resource/mozmill/README.md
@@ -1,8 +1,9 @@
 <!-- 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/. -->
 
-These folders are pulled from https://github.com/mozautomation/mozmill/tree/master/mozmill/mozmill/extension/resource.
+These folders are pulled from:
+https://github.com/mozilla/mozmill/tree/master/mozmill/mozmill/extension/resource
 
 To update them, simply checkout the mozmill repo at https://github.com/mozautomation/mozmill, 
 then copy and paste the 'driver' and 'stdlib' folders to this location. 
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -1,6 +1,6 @@
 {
     "talos.zip": {
-        "url": "http://build.mozilla.org/talos/zips/talos.dd8466b5d8d0.zip",
+        "url": "http://build.mozilla.org/talos/zips/talos.07322bbe0f7d.zip",
         "path": ""
     }
 }
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -658,28 +658,28 @@ function Livemark(aLivemarkInfo)
 {
   this.title = aLivemarkInfo.title;
   this.parentId = aLivemarkInfo.parentId;
   this.index = aLivemarkInfo.index;
 
   this._status = Ci.mozILivemark.STATUS_READY;
 
   // Hash of resultObservers, hashed by container.
-  this._resultObservers = new WeakMap();
-  // This keeps a list of the containers used as keys in the weakmap, since
+  this._resultObservers = new Map();
+  // This keeps a list of the containers used as keys in the map, since
   // it's not iterable.  In future may use an iterable Map.
   this._resultObserversList = [];
 
   // Sorted array of objects representing livemark children in the form
   // { uri, title, visited }.
   this._children = [];
 
   // Keeps a separate array of nodes for each requesting container, hashed by
   // the container itself.
-  this._nodes = new WeakMap();
+  this._nodes = new Map();
 
   this._guid = "";
   this._lastModified = 0;
 
   this.loadGroup = null;
   this.feedURI = null;
   this.siteURI = null;
   this.expireTime = 0;
--- a/toolkit/components/places/nsPlacesExportService.cpp
+++ b/toolkit/components/places/nsPlacesExportService.cpp
@@ -183,38 +183,16 @@ nsPlacesExportService::Init()
   NS_ENSURE_TRUE(mAnnotationService, NS_ERROR_OUT_OF_MEMORY);
   mBookmarksService = do_GetService(NS_NAVBOOKMARKSSERVICE_CONTRACTID);
   NS_ENSURE_TRUE(mBookmarksService, NS_ERROR_OUT_OF_MEMORY);
   mLivemarkService = do_GetService(NS_LIVEMARKSERVICE_CONTRACTID);
   NS_ENSURE_TRUE(mLivemarkService, NS_ERROR_OUT_OF_MEMORY);
   return NS_OK;
 }
 
-// SyncChannelStatus
-//
-//    If a function returns an error, we need to set the channel status to be
-//    the same, but only if the channel doesn't have its own error. This returns
-//    the error code that should be sent to OnStopRequest.
-static nsresult
-SyncChannelStatus(nsIChannel* channel, nsresult status)
-{
-  nsresult channelStatus;
-  channel->GetStatus(&channelStatus);
-  if (NS_FAILED(channelStatus))
-    return channelStatus;
-
-  if (NS_SUCCEEDED(status))
-    return NS_OK; // caller and the channel are happy
-
-  // channel was OK, but caller wasn't: set the channel state
-  channel->Cancel(status);
-  return status;
-}
-
-
 static char kFileIntro[] =
     "<!DOCTYPE NETSCAPE-Bookmark-file-1>" NS_LINEBREAK
     // Note: we write bookmarks in UTF-8
     "<!-- This is an automatically generated file." NS_LINEBREAK
     "     It will be read and overwritten." NS_LINEBREAK
     "     DO NOT EDIT! -->" NS_LINEBREAK
     "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">" NS_LINEBREAK
     "<TITLE>Bookmarks</TITLE>" NS_LINEBREAK;
--- a/toolkit/components/social/FrameWorker.jsm
+++ b/toolkit/components/social/FrameWorker.jsm
@@ -28,17 +28,17 @@ function getFrameWorkerHandle(url, clien
   // first create the client port we are going to use.  Later we will
   // message the worker to create the worker port.
   let portid = _nextPortId++;
   let clientPort = new ClientPort(portid, clientWindow);
 
   let existingWorker = workerCache[url];
   if (!existingWorker) {
     // setup the worker and add this connection to the pending queue
-    let worker = new FrameWorker(url, clientWindow, name);
+    let worker = new FrameWorker(url, name);
     worker.pendingPorts.push(clientPort);
     existingWorker = workerCache[url] = worker;
   } else {
     // already have a worker - either queue or make the connection.
     if (existingWorker.loaded) {
       try {
         clientPort._createWorkerAndEntangle(existingWorker);
       }
@@ -248,21 +248,16 @@ function makeHiddenFrame() {
   return iframe;
 }
 
 function WorkerHandle(port, worker) {
   this.port = port;
   this._worker = worker;
 }
 WorkerHandle.prototype = {
-  __exposedProps__: {
-    port: "r",
-    terminate: "r"
-  },
-
   // XXX - workers have no .close() method, but *do* have a .terminate()
   // method which we should implement. However, the worker spec doesn't define
   // a callback to be made in the worker when this happens - it all just dies.
   // TODO: work out a sane impl for 'terminate'.
   terminate: function terminate() {
     this._worker.terminate();
   }
 };
@@ -324,36 +319,36 @@ function initClientMessageHandler(worker
  * Client side of the entangled ports. The ClientPort is used by both XUL
  * windows and Content windows to communicate with the worker
  *
  * constructor:
  * @param {integer} portid
  * @param {nsiDOMWindow} clientWindow, optional
  */
 function ClientPort(portid, clientWindow) {
-  this._clientWindow = clientWindow
+  this._clientWindow = clientWindow;
   this._window = null;
   // messages posted to the worker before the worker has loaded.
   this._pendingMessagesOutgoing = [];
   AbstractPort.call(this, portid);
 }
 
 ClientPort.prototype = {
   __exposedProps__: {
-    'port': 'r',
-    'onmessage': 'rw',
-    'postMessage': 'r',
-    'close': 'r'
+    onmessage: "rw",
+    postMessage: "r",
+    close: "r",
+    toString: "r"
   },
   __proto__: AbstractPort.prototype,
   _portType: "client",
 
   _JSONParse: function fw_ClientPort_JSONParse(data) {
     if (this._clientWindow) {
-      return this._clientWindow.JSON.parse(data);
+      return XPCNativeWrapper.unwrap(this._clientWindow).JSON.parse(data);
     }
     return JSON.parse(data);
   },
 
   _createWorkerAndEntangle: function fw_ClientPort_createWorkerAndEntangle(worker) {
     this._window = worker.frame.contentWindow;
     worker.ports[this._portid] = this;
     this._postControlMessage("port-create");
@@ -378,11 +373,12 @@ ClientPort.prototype = {
     if (!this._portid) {
       return; // already closed.
     }
     // a leaky abstraction due to the worker spec not specifying how the
     // other end of a port knows it is closing.
     this.postMessage({topic: "social.port-closing"});
     AbstractPort.prototype.close.call(this);
     this._window = null;
+    this._clientWindow = null;
     this._pendingMessagesOutgoing = null;
   }
 }
--- a/toolkit/components/social/Makefile.in
+++ b/toolkit/components/social/Makefile.in
@@ -10,15 +10,16 @@ VPATH     = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 EXTRA_JS_MODULES = \
   FrameWorker.jsm \
   MessagePortBase.jsm \
   MessagePortWorker.js \
   SocialService.jsm \
   WorkerAPI.jsm \
+  MozSocialAPI.jsm \
   $(NULL)
 
 TEST_DIRS += \
   test \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/toolkit/components/social/MessagePortBase.jsm
+++ b/toolkit/components/social/MessagePortBase.jsm
@@ -24,58 +24,57 @@ AbstractPort.prototype = {
 
   // and concrete methods shared by client and workers.
   toString: function fw_AbstractPort_toString() {
     return "MessagePort(portType='" + this._portType + "', portId=" + this._portid + ")";
   },
   _JSONParse: function fw_AbstractPort_JSONParse(data) JSON.parse(data),
 
  _postControlMessage: function fw_AbstractPort_postControlMessage(topic, data) {
-    let postData = {portTopic: topic,
-                    portId: this._portid,
-                    portFromType: this._portType,
-                    data: data,
-                    __exposedProps__: {
-                      portTopic: 'r',
-                      portId: 'r',
-                      portFromType: 'r',
-                      data: 'r'
-                    }
-                   };
+    let postData = {
+      portTopic: topic,
+      portId: this._portid,
+      portFromType: this._portType,
+      data: data
+    };
     this._dopost(postData);
   },
 
   _onmessage: function fw_AbstractPort_onmessage(data) {
     // See comments in postMessage below - we work around a cloning
     // issue by using JSON for these messages.
     // Further, we allow the workers to override exactly how the JSON parsing
     // is done - we try and do such parsing in the client window so things
     // like prototype overrides on Array work as expected.
     data = this._JSONParse(data);
     if (!this._handler) {
       this._pendingMessagesIncoming.push(data);
-    }
-    else {
+    } else {
       try {
-        this._handler({data: data,
-                       __exposedProps__: {data: 'r'}
-                      });
-      }
-      catch (ex) {
+        this._handler({
+          data: data,
+          __exposedProps__: {
+            data: 'r'
+          }
+        });
+      } catch (ex) {
         this._onerror(ex);
       }
     }
   },
 
   set onmessage(handler) { // property setter for onmessage
     this._handler = handler;
     while (this._pendingMessagesIncoming.length) {
       this._onmessage(this._pendingMessagesIncoming.shift());
     }
   },
+  get onmessage() {
+    return this._handler;
+  },
 
   /**
    * postMessage
    *
    * Send data to the onmessage handler on the other end of the port.  The
    * data object should have a topic property.
    *
    * @param {jsobj} data
new file mode 100644
--- /dev/null
+++ b/toolkit/components/social/MozSocialAPI.jsm
@@ -0,0 +1,130 @@
+/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "SocialService", "resource://gre/modules/SocialService.jsm");
+
+const EXPORTED_SYMBOLS = ["MozSocialAPI"];
+
+var MozSocialAPI = {
+  _enabled: false,
+  set enabled(val) {
+    let enable = !!val;
+    if (enable == this._enabled) {
+      return;
+    }
+    this._enabled = enable;
+
+    if (enable) {
+      Services.obs.addObserver(injectController, "document-element-inserted", false);
+    } else {
+      Services.obs.removeObserver(injectController, "document-element-inserted", false);
+    }
+  }
+};
+
+// Called on document-element-inserted, checks that the API should be injected,
+// and then calls attachToWindow as appropriate
+function injectController(doc, topic, data) {
+  try {
+    let window = doc.defaultView;
+    if (!window)
+      return;
+
+    var containingBrowser = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                                  .getInterface(Ci.nsIWebNavigation)
+                                  .QueryInterface(Ci.nsIDocShell)
+                                  .chromeEventHandler;
+
+    // If the containing browser isn't one of the social browsers, nothing to
+    // do here.
+    // XXX this is app-specific, might want some mechanism for consumers to
+    // whitelist other IDs/windowtypes  
+    if (!(containingBrowser.id == "social-sidebar-browser" ||
+          containingBrowser.id == "social-notification-browser")) {
+      return;
+    }
+
+    let origin = containingBrowser.getAttribute("origin");
+    if (!origin) {
+      return;
+    }
+
+    SocialService.getProvider(origin, function(provider) {
+      if (provider && provider.workerURL) {
+        attachToWindow(provider, window);
+      }
+    });
+  } catch(e) {
+    Cu.reportError("MozSocialAPI injectController: unable to attachToWindow for " + doc.location + ": " + e);
+  }
+}
+
+// Loads mozSocial support functions associated with provider into targetWindow
+function attachToWindow(provider, targetWindow) {
+  let origin = provider.origin;
+  if (!provider.enabled) {
+    throw new Error("MozSocialAPI: cannot attach disabled provider " + origin);
+  }
+
+  let targetDocURI = targetWindow.document.documentURIObject;
+  if (provider.origin != targetDocURI.prePath) {
+    throw new Error("MozSocialAPI: cannot attach " + origin + " to " + targetDocURI.spec);
+  }
+
+  var port = provider._getWorkerPort(targetWindow);
+
+  let mozSocialObj = {
+    // Use a method for backwards compat with existing providers, but we
+    // should deprecate this in favor of a simple .port getter.
+    getWorker: function() {
+      return {
+        port: port,
+        __exposedProps__: {
+          port: "r"
+        }
+      };
+    },
+    hasBeenIdleFor: function () {
+      return false;
+    }
+  };
+
+  let contentObj = Cu.createObjectIn(targetWindow);
+  let propList = {};
+  for (let prop in mozSocialObj) {
+    propList[prop] = {
+      enumerable: true,
+      configurable: true,
+      writable: true,
+      value: mozSocialObj[prop]
+    };
+  }
+  Object.defineProperties(contentObj, propList);
+  Cu.makeObjectPropsNormal(contentObj);
+
+  targetWindow.navigator.wrappedJSObject.__defineGetter__("mozSocial", function() {
+    // We do this in a getter, so that we create these objects
+    // only on demand (this is a potential concern, since
+    // otherwise we might add one per iframe, and keep them
+    // alive for as long as the window is alive).
+    delete targetWindow.navigator.wrappedJSObject.mozSocial;
+    return targetWindow.navigator.wrappedJSObject.mozSocial = contentObj;
+  });
+
+  targetWindow.addEventListener("unload", function () {
+    // We want to close the port, but also want the target window to be
+    // able to use the port during an unload event they setup - so we
+    // set a timer which will fire after the unload events have all fired.
+    schedule(function () { port.close(); });
+  });
+}
+
+function schedule(callback) {
+  Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
+}
--- a/toolkit/components/social/SocialService.jsm
+++ b/toolkit/components/social/SocialService.jsm
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const EXPORTED_SYMBOLS = ["SocialService"];
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/MozSocialAPI.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "getFrameWorkerHandle", "resource://gre/modules/FrameWorker.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WorkerAPI", "resource://gre/modules/WorkerAPI.jsm");
 
 /**
  * The SocialService is the public API to social providers - it tracks which
  * providers are installed and enabled, and is the entry-point for access to
  * the provider itself.
@@ -24,24 +25,27 @@ let SocialServiceInternal = {
   get providerArray() {
     return [p for ([, p] of Iterator(this.providers))];
   }
 };
 
 XPCOMUtils.defineLazyGetter(SocialServiceInternal, "providers", function () {
   // Initialize the service (add a pref observer)
   function prefObserver(subject, topic, data) {
-    SocialService._setEnabled(Services.prefs.getBoolPref(data));
+    SocialService._setEnabled(Services.prefs.getBoolPref("social.enabled"));
   }
   Services.prefs.addObserver("social.enabled", prefObserver, false);
   Services.obs.addObserver(function xpcomShutdown() {
     Services.obs.removeObserver(xpcomShutdown, "xpcom-shutdown");
     Services.prefs.removeObserver("social.enabled", prefObserver);
   }, "xpcom-shutdown", false);
 
+  // Initialize the MozSocialAPI
+  MozSocialAPI.enabled = SocialServiceInternal.enabled;
+
   // Now retrieve the providers
   let providers = {};
   let MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
   let prefs = MANIFEST_PREFS.getChildList("", {});
   prefs.forEach(function (pref) {
     try {
       var manifest = JSON.parse(MANIFEST_PREFS.getCharPref(pref));
       if (manifest && typeof(manifest) == "object") {
@@ -72,16 +76,17 @@ const SocialService = {
       return;
 
     Services.prefs.setBoolPref("social.enabled", enable);
     this._setEnabled(enable);
   },
   _setEnabled: function _setEnabled(enable) {
     SocialServiceInternal.providerArray.forEach(function (p) p.enabled = enable);
     SocialServiceInternal.enabled = enable;
+    MozSocialAPI.enabled = enable;
     Services.obs.notifyObservers(null, "social:pref-changed", enable ? "enabled" : "disabled");
   },
 
   // Adds a provider given a manifest, and returns the added provider.
   addProvider: function addProvider(manifest, onDone) {
     if (SocialServiceInternal.providers[manifest.origin])
       throw new Error("SocialService.addProvider: provider with this origin already exists");
 
--- a/toolkit/components/social/test/browser/browser_workerAPI.js
+++ b/toolkit/components/social/test/browser/browser_workerAPI.js
@@ -27,17 +27,17 @@ let tests = {
   testInitializeWorker: function(next) {
     ok(provider.workerAPI, "provider has a workerAPI");
     is(provider.workerAPI.initialized, false, "workerAPI is not yet initialized");
   
     let port = provider.port;
     ok(port, "should be able to get a port from the provider");
   
     port.onmessage = function onMessage(event) {
-      let {topic, data} = event.data;
+      let topic = event.data.topic;
       if (topic == "test-initialization-complete") {
         is(provider.workerAPI.initialized, true, "workerAPI is now initialized");
         next();
       }
     }
     port.postMessage({topic: "test-initialization"});
   },
 
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc
@@ -145,25 +145,30 @@ bool GetThreadRegisters(ThreadInfo* info
       return false;
     }
   }
 #endif
 
   return true;
 }
 
+// All interesting auvx entry types are below AT_SYSINFO_EHDR
+#define AT_MAX AT_SYSINFO_EHDR
+
 LinuxDumper::LinuxDumper(int pid)
     : pid_(pid),
       threads_suspended_(false),
       threads_(&allocator_, 8),
-      mappings_(&allocator_) {
+      mappings_(&allocator_),
+      auxv_(&allocator_, AT_MAX + 1) {
 }
 
 bool LinuxDumper::Init() {
-  return EnumerateThreads(&threads_) &&
+  return ReadAuxv() &&
+         EnumerateThreads(&threads_) &&
          EnumerateMappings(&mappings_);
 }
 
 bool LinuxDumper::ThreadsAttach() {
   if (threads_suspended_)
     return true;
   for (size_t i = 0; i < threads_.size(); ++i) {
     if (!AttachThread(threads_[i])) {
@@ -266,58 +271,58 @@ LinuxDumper::ElfFileIdentifierForMapping
     return false;
   }
 
   bool success = FileID::ElfFileIdentifierFromMappedFile(base, identifier);
   sys_munmap(base, st.st_size);
   return success;
 }
 
-void*
-LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
+bool
+LinuxDumper::ReadAuxv() {
   char auxv_path[80];
-  BuildProcPath(auxv_path, pid, "auxv");
+  BuildProcPath(auxv_path, pid_, "auxv");
 
   // If BuildProcPath errors out due to invalid input, we'll handle it when
   // we try to sys_open the file.
 
-  // Find the AT_SYSINFO_EHDR entry for linux-gate.so
-  // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
-  // information.
   int fd = sys_open(auxv_path, O_RDONLY, 0);
   if (fd < 0) {
-    return NULL;
+    return false;
   }
 
   elf_aux_entry one_aux_entry;
+  bool res = false;
   while (sys_read(fd,
                   &one_aux_entry,
                   sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
          one_aux_entry.a_type != AT_NULL) {
-    if (one_aux_entry.a_type == AT_SYSINFO_EHDR) {
-      close(fd);
-      return reinterpret_cast<void*>(one_aux_entry.a_un.a_val);
+    if (one_aux_entry.a_type <= AT_MAX) {
+      auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val;
+      res = true;
     }
   }
   close(fd);
-  return NULL;
+  return res;
 }
 
 bool
 LinuxDumper::EnumerateMappings(wasteful_vector<MappingInfo*>* result) const {
   char maps_path[80];
   BuildProcPath(maps_path, pid_, "maps");
 
   // linux_gate_loc is the beginning of the kernel's mapping of
   // linux-gate.so in the process.  It doesn't actually show up in the
-  // maps list as a filename, so we use the aux vector to find it's
-  // load location and special case it's entry when creating the list
-  // of mappings.
+  // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR
+  // aux vector entry, which gives the information necessary to special
+  // case its entry when creating the list of mappings.
+  // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
+  // information.
   const void* linux_gate_loc;
-  linux_gate_loc = FindBeginningOfLinuxGateSharedLibrary(pid_);
+  linux_gate_loc = reinterpret_cast<void *>(auxv_[AT_SYSINFO_EHDR]);
 
   const int fd = sys_open(maps_path, O_RDONLY, 0);
   if (fd < 0)
     return false;
   LineReader* const line_reader = new(allocator_) LineReader(fd);
 
   const char* line;
   unsigned line_len;
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h
@@ -65,16 +65,19 @@ typedef struct
 
 #if !defined(AT_SYSINFO_EHDR)
 #define AT_SYSINFO_EHDR 33
 #endif
 #endif  // __ANDROID__
 #elif defined(__x86_64__)
 typedef Elf64_auxv_t elf_aux_entry;
 #endif
+
+typedef typeof(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t;
+
 // When we find the VDSO mapping in the process's address space, this
 // is the name we use for it when writing it to the minidump.
 // This should always be less than NAME_MAX!
 const char kLinuxGateLibraryName[] = "linux-gate.so";
 
 // We produce one of these structures for each thread in the crashed process.
 struct ThreadInfo {
   pid_t tid;    // thread id
@@ -140,16 +143,17 @@ class LinuxDumper {
   // Read information about the given thread. Returns true on success. One must
   // have called |ThreadsAttach| first.
   bool ThreadInfoGet(ThreadInfo* info);
 
   // These are only valid after a call to |Init|.
   const wasteful_vector<pid_t> &threads() { return threads_; }
   const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
   const MappingInfo* FindMapping(const void* address) const;
+  const wasteful_vector<elf_aux_val_t> &auxv() { return auxv_; }
 
   // Find a block of memory to take as the stack given the top of stack pointer.
   //   stack: (output) the lowest address in the memory area
   //   stack_len: (output) the length of the memory area
   //   stack_top: the current top of the stack
   bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
 
   PageAllocator* allocator() { return &allocator_; }
@@ -162,30 +166,26 @@ class LinuxDumper {
   // character array that is overwritten, and node is the final node
   // without any slashes.
   void BuildProcPath(char* path, pid_t pid, const char* node) const;
 
   // Generate a File ID from the .text section of a mapped entry
   bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
                                    uint8_t identifier[sizeof(MDGUID)]);
 
-  // Utility method to find the location of where the kernel has
-  // mapped linux-gate.so in memory(shows up in /proc/pid/maps as
-  // [vdso], but we can't guarantee that it's the only virtual dynamic
-  // shared object.  Parsing the auxilary vector for AT_SYSINFO_EHDR
-  // is the safest way to go.)
-  void* FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const;
  private:
+  bool ReadAuxv();
   bool EnumerateMappings(wasteful_vector<MappingInfo*>* result) const;
   bool EnumerateThreads(wasteful_vector<pid_t>* result) const;
 
   const pid_t pid_;
 
   mutable PageAllocator allocator_;
 
   bool threads_suspended_;
   wasteful_vector<pid_t> threads_;  // the ids of all the threads
   wasteful_vector<MappingInfo*> mappings_;  // info from /proc/<pid>/maps
+  wasteful_vector<elf_aux_val_t> auxv_;  // info from /proc/<pid>/auxv
 };
 
 }  // namespace google_breakpad
 
 #endif  // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest.cc
@@ -158,17 +158,17 @@ TEST(LinuxDumperTest, BuildProcPath) {
 #endif
 }
 
 #if !defined(__ARM_EABI__)
 TEST(LinuxDumperTest, MappingsIncludeLinuxGate) {
   LinuxDumper dumper(getpid());
   ASSERT_TRUE(dumper.Init());
 
-  void* linux_gate_loc = dumper.FindBeginningOfLinuxGateSharedLibrary(getpid());
+  void* linux_gate_loc = reinterpret_cast<void *>(dumper.auxv()[AT_SYSINFO_EHDR]);
   ASSERT_TRUE(linux_gate_loc);
   bool found_linux_gate = false;
 
   const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
   const MappingInfo* mapping;
   for (unsigned i = 0; i < mappings.size(); ++i) {
     mapping = mappings[i];
     if (!strcmp(mapping->name, kLinuxGateLibraryName)) {
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc
@@ -465,39 +465,19 @@ class MinidumpWriter {
     dumper_.ThreadsDetach();
   }
 
   bool HaveCrashedThread() const {
     return ucontext_ != NULL;
   }
 
   bool Dump() {
-    // The dynamic linker makes information available that helps gdb find all
-    // DSOs loaded into the program. If we can access this information, we dump
-    // it to a MD_LINUX_DSO_DEBUG stream.
-    struct r_debug* r_debug = NULL;
-    uint32_t dynamic_length = 0;
-#if !defined(__ANDROID__)
-    for (int i = 0;;) {
-      ElfW(Dyn) dyn;
-      dynamic_length += sizeof(dyn);
-      dumper_.CopyFromProcess(&dyn, crashing_tid_, _DYNAMIC+i++, sizeof(dyn));
-      if (dyn.d_tag == DT_DEBUG) {
-        r_debug = (struct r_debug*)dyn.d_un.d_ptr;
-        continue;
-      } else if (dyn.d_tag == DT_NULL)
-        break;
-    }
-#endif
-
     // A minidump file contains a number of tagged streams. This is the number
     // of stream which we write.
-    unsigned kNumWriters = 12;
-    if (r_debug)
-      ++kNumWriters;
+    unsigned kNumWriters = 13;
 
     TypedMDRVA<MDRawHeader> header(&minidump_writer_);
     TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
     if (!header.Allocate())
       return false;
     if (!dir.AllocateArray(kNumWriters))
       return false;
     memset(header.get(), 0, sizeof(MDRawHeader));
@@ -566,22 +546,20 @@ class MinidumpWriter {
       NullifyDirectoryEntry(&dirent);
     dir.CopyIndex(dir_index++, &dirent);
 
     dirent.stream_type = MD_LINUX_MAPS;
     if (!WriteProcFile(&dirent.location, crashing_tid_, "maps"))
       NullifyDirectoryEntry(&dirent);
     dir.CopyIndex(dir_index++, &dirent);
 
-    if (r_debug) {
-      dirent.stream_type = MD_LINUX_DSO_DEBUG;
-      if (!WriteDSODebugStream(&dirent, r_debug, dynamic_length))
-        NullifyDirectoryEntry(&dirent);
-      dir.CopyIndex(dir_index++, &dirent);
-    }
+    dirent.stream_type = MD_LINUX_DSO_DEBUG;
+    if (!WriteDSODebugStream(&dirent))
+      NullifyDirectoryEntry(&dirent);
+    dir.CopyIndex(dir_index++, &dirent);
 
     // If you add more directory entries, don't forget to update kNumWriters,
     // above.
 
     dumper_.ThreadsDetach();
     return true;
   }
 
@@ -1032,23 +1010,66 @@ class MinidumpWriter {
     dirent->location = si.location();
 
     WriteCPUInformation(si.get());
     WriteOSInformation(si.get());
 
     return true;
   }
 
-  bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
-                           uint32_t dynamic_length) {
+  bool WriteDSODebugStream(MDRawDirectory* dirent) {
 #if defined(__ANDROID__)
     return false;
 #else
-    // The caller provided us with a pointer to "struct r_debug". We can
-    // look up the "r_map" field to get a linked list of all loaded DSOs.
+    ElfW(Phdr) *phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_.auxv()[AT_PHDR]);
+    char *base;
+    int phnum = dumper_.auxv()[AT_PHNUM];
+    if (!phnum || !phdr)
+      return false;
+
+    // Assume the program base is at the beginning of the same page as the PHDR
+    base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff);
+
+    // Search for the program PT_DYNAMIC segment
+    ElfW(Addr) dyn_addr = 0;
+    for (; phnum >= 0; phnum--, phdr++) {
+      ElfW(Phdr) ph;
+      dumper_.CopyFromProcess(&ph, crashing_tid_, phdr, sizeof(ph));
+      // Adjust base address with the virtual address of the PT_LOAD segment
+      // corresponding to offset 0
+      if (ph.p_type == PT_LOAD && ph.p_offset == 0)
+        base -= ph.p_vaddr;
+      if (ph.p_type == PT_DYNAMIC)
+        dyn_addr = ph.p_vaddr;
+    }
+    if (!dyn_addr)
+      return false;
+
+    ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base);
+
+    // The dynamic linker makes information available that helps gdb find all
+    // DSOs loaded into the program. If this information is indeed available,
+    // dump it to a MD_LINUX_DSO_DEBUG stream.
+    struct r_debug* r_debug = NULL;
+    uint32_t dynamic_length = 0;
+
+    for (int i = 0;;) {
+      ElfW(Dyn) dyn;
+      dynamic_length += sizeof(dyn);
+      dumper_.CopyFromProcess(&dyn, crashing_tid_, dynamic+i++, sizeof(dyn));
+      if (dyn.d_tag == DT_DEBUG) {
+        r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
+        continue;
+      } else if (dyn.d_tag == DT_NULL) {
+        break;
+      }
+    }
+
+    // The "r_map" field of that r_debug struct contains a linked list of all
+    // loaded DSOs.
     // Our list of DSOs potentially is different from the ones in the crashing
     // process. So, we have to be careful to never dereference pointers
     // directly. Instead, we use CopyFromProcess() everywhere.
     // See <link.h> for a more detailed discussion of the how the dynamic
     // loader communicates with debuggers.
 
     // Count the number of loaded DSOs
     int dso_count = 0;
@@ -1101,20 +1122,20 @@ class MinidumpWriter {
     dirent->stream_type = MD_LINUX_DSO_DEBUG;
     dirent->location = debug.location();
 
     debug.get()->version = debug_entry.r_version;
     debug.get()->map = linkmap_rva;
     debug.get()->dso_count = dso_count;
     debug.get()->brk = (void*)debug_entry.r_brk;
     debug.get()->ldbase = (void*)debug_entry.r_ldbase;
-    debug.get()->dynamic = (void*)&_DYNAMIC;
+    debug.get()->dynamic = dynamic;
 
     char *dso_debug_data = new char[dynamic_length];
-    dumper_.CopyFromProcess(dso_debug_data, crashing_tid_, &_DYNAMIC,
+    dumper_.CopyFromProcess(dso_debug_data, crashing_tid_, dynamic,
                             dynamic_length);
     debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
     delete[] dso_debug_data;
 
     return true;
 #endif  // __ANDROID__
   }
 
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -150,27 +150,39 @@ static const XP_CHAR dumpFileExtension[]
 static const XP_CHAR extraFileExtension[] = {'.', 'e', 'x', 't',
                                              'r', 'a', '\0'}; // .extra
 
 static google_breakpad::ExceptionHandler* gExceptionHandler = nsnull;
 
 static XP_CHAR* pendingDirectory;
 static XP_CHAR* crashReporterPath;
 
-// if this is false, we don't launch the crash reporter
+// If this is false, we don't launch the crash reporter
 static bool doReport = true;
 
+// If this is true, we don't have a crash reporter
+static bool headlessClient = false;
+
 // if this is true, we pass the exception on to the OS crash reporter
 static bool showOSCrashReporter = false;
 
 // The time of the last recorded crash, as a time_t value.
 static time_t lastCrashTime = 0;
 // The pathname of a file to store the crash time in
 static XP_CHAR lastCrashTimeFilename[XP_PATH_MAX] = {0};
 
+// A marker file to hold the path to the last dump written, which
+// will be checked on startup.
+static XP_CHAR crashMarkerFilename[XP_PATH_MAX] = {0};
+
+// Whether we've already looked for the marker file.
+static bool lastRunCrashID_checked = false;
+// The minidump ID contained in the marker file.
+static nsString* lastRunCrashID = nsnull;
+
 // these are just here for readability
 static const char kCrashTimeParameter[] = "CrashTime=";
 static const int kCrashTimeParameterLen = sizeof(kCrashTimeParameter)-1;
 
 static const char kTimeSinceLastCrashParameter[] = "SecondsSinceLastCrash=";
 static const int kTimeSinceLastCrashParameterLen =
                                      sizeof(kTimeSinceLastCrashParameter)-1;
 
@@ -309,17 +321,17 @@ static cpu_type_t pref_cpu_types[2] = {
 #elif defined(__ppc__)
                                  CPU_TYPE_POWERPC,
 #endif
                                  CPU_TYPE_ANY };
 
 static posix_spawnattr_t spawnattr;
 #endif
 
-#if defined(__ANDROID__)
+#if defined(MOZ_WIDGET_ANDROID)
 // Android builds use a custom library loader,
 // so the embedding will provide a list of shared
 // libraries that are mapped into anonymous mappings.
 typedef struct {
   std::string name;
   std::string debug_id;
   uintptr_t   start_address;
   size_t      length;
@@ -411,16 +423,39 @@ bool MinidumpCallback(const XP_CHAR* dum
 
   static XP_CHAR extraDataPath[XP_PATH_MAX];
   size = XP_PATH_MAX;
   p = Concat(extraDataPath, dump_path, &size);
   p = Concat(p, XP_PATH_SEPARATOR, &size);
   p = Concat(p, minidump_id, &size);
   Concat(p, extraFileExtension, &size);
 
+  if (headlessClient) {
+    // Leave a marker indicating that there was a crash.
+#if defined(XP_WIN32)
+    HANDLE hFile = CreateFile(crashMarkerFilename, GENERIC_WRITE, 0,
+                              NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                              NULL);
+    if(hFile != INVALID_HANDLE_VALUE) {
+      DWORD nBytes;
+      WriteFile(hFile, minidumpPath, 2*wcslen(minidumpPath), &nBytes, NULL);
+      CloseHandle(hFile);
+    }
+#elif defined(XP_UNIX)
+    int fd = sys_open(crashMarkerFilename,
+                      O_WRONLY | O_CREAT | O_TRUNC,
+                      0600);
+    if (fd != -1) {
+      ssize_t ignored = sys_write(fd, minidumpPath, my_strlen(minidumpPath));
+      (void)ignored;
+      sys_close(fd);
+    }
+#endif
+  }
+
   char oomAllocationSizeBuffer[32];
   int oomAllocationSizeBufferLen = 0;
   if (gOOMAllocationSize) {
     XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer, 10);
     oomAllocationSizeBufferLen = my_strlen(oomAllocationSizeBuffer);
   }
 
   // calculate time since last crash (if possible), and store
@@ -466,24 +501,16 @@ bool MinidumpCallback(const XP_CHAR* dum
       ssize_t ignored = sys_write(fd, crashTimeString, crashTimeStringLen);
       (void)ignored;
       sys_close(fd);
     }
 #endif
   }
 
 #if defined(XP_WIN32)
-  XP_CHAR cmdLine[CMDLINE_SIZE];
-  size = CMDLINE_SIZE;
-  p = Concat(cmdLine, L"\"", &size);
-  p = Concat(p, crashReporterPath, &size);
-  p = Concat(p, L"\" \"", &size);
-  p = Concat(p, minidumpPath, &size);
-  Concat(p, L"\"", &size);
-
   if (!crashReporterAPIData->IsEmpty()) {
     // write out API data
     HANDLE hFile = CreateFile(extraDataPath, GENERIC_WRITE, 0,
                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
                               NULL);
     if(hFile != INVALID_HANDLE_VALUE) {
       DWORD nBytes;
       WriteFile(hFile, crashReporterAPIData->get(),
@@ -534,16 +561,24 @@ bool MinidumpCallback(const XP_CHAR* dum
       CloseHandle(hFile);
     }
   }
 
   if (!doReport) {
     return returnValue;
   }
 
+  XP_CHAR cmdLine[CMDLINE_SIZE];
+  size = CMDLINE_SIZE;
+  p = Concat(cmdLine, L"\"", &size);
+  p = Concat(p, crashReporterPath, &size);
+  p = Concat(p, L"\" \"", &size);
+  p = Concat(p, minidumpPath, &size);
+  Concat(p, L"\"", &size);
+
   STARTUPINFO si;
   PROCESS_INFORMATION pi;
 
   ZeroMemory(&si, sizeof(si));
   si.cb = sizeof(si);
   si.dwFlags = STARTF_USESHOWWINDOW;
   si.wShowWindow = SW_SHOWNORMAL;
   ZeroMemory(&pi, sizeof(pi));
@@ -612,17 +647,17 @@ bool MinidumpCallback(const XP_CHAR* dum
     return false;
 
 #else // !XP_MACOSX
   pid_t pid = sys_fork();
 
   if (pid == -1)
     return false;
   else if (pid == 0) {
-#if !defined(__ANDROID__)
+#if !defined(MOZ_WIDGET_ANDROID)
     // need to clobber this, as libcurl might load NSS,
     // and we want it to load the system NSS.
     unsetenv("LD_LIBRARY_PATH");
     (void) execl(crashReporterPath,
                  crashReporterPath, minidumpPath, (char*)0);
 #else
     // Invoke the reportCrash activity using am
     (void) execlp("/system/bin/am",
@@ -683,28 +718,31 @@ namespace {
     return true;
   }
 }
 
 
 nsresult SetExceptionHandler(nsIFile* aXREDirectory,
                              bool force/*=false*/)
 {
-  nsresult rv;
-
   if (gExceptionHandler)
     return NS_ERROR_ALREADY_INITIALIZED;
 
   const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE");
   if (envvar && *envvar && !force)
     return NS_OK;
 
+#if defined(MOZ_WIDGET_GONK)
+  doReport = false;
+  headlessClient = true;
+#else
   // this environment variable prevents us from launching
   // the crash reporter client
   doReport = ShouldReport();
+#endif
 
   // allocate our strings
   crashReporterAPIData = new nsCString();
   NS_ENSURE_TRUE(crashReporterAPIData, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ASSERTION(!crashReporterAPILock, "Shouldn't have a lock yet");
   crashReporterAPILock = new Mutex("crashReporterAPILock");
   NS_ASSERTION(!notesFieldLock, "Shouldn't have a lock yet");
@@ -714,47 +752,47 @@ nsresult SetExceptionHandler(nsIFile* aX
     new nsDataHashtable<nsCStringHashKey,nsCString>();
   NS_ENSURE_TRUE(crashReporterAPIData_Hash, NS_ERROR_OUT_OF_MEMORY);
 
   crashReporterAPIData_Hash->Init();
 
   notesField = new nsCString();
   NS_ENSURE_TRUE(notesField, NS_ERROR_OUT_OF_MEMORY);
 
-  // locate crashreporter executable
-  nsCOMPtr<nsIFile> exePath;
-  rv = aXREDirectory->Clone(getter_AddRefs(exePath));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (!headlessClient) {
+    // locate crashreporter executable
+    nsCOMPtr<nsIFile> exePath;
+    nsresult rv = aXREDirectory->Clone(getter_AddRefs(exePath));
+    NS_ENSURE_SUCCESS(rv, rv);
 
 #if defined(XP_MACOSX)
-  exePath->Append(NS_LITERAL_STRING("crashreporter.app"));
-  exePath->Append(NS_LITERAL_STRING("Contents"));
-  exePath->Append(NS_LITERAL_STRING("MacOS"));
+    exePath->Append(NS_LITERAL_STRING("crashreporter.app"));
+    exePath->Append(NS_LITERAL_STRING("Contents"));
+    exePath->Append(NS_LITERAL_STRING("MacOS"));
 #endif
 
-  exePath->AppendNative(NS_LITERAL_CSTRING(CRASH_REPORTER_FILENAME));
+    exePath->AppendNative(NS_LITERAL_CSTRING(CRASH_REPORTER_FILENAME));
 
 #ifdef XP_WIN32
-  nsString crashReporterPath_temp;
-
-  exePath->GetPath(crashReporterPath_temp);
-  crashReporterPath = ToNewUnicode(crashReporterPath_temp);
+    nsString crashReporterPath_temp;
+
+    exePath->GetPath(crashReporterPath_temp);
+    crashReporterPath = ToNewUnicode(crashReporterPath_temp);
 #elif !defined(__ANDROID__)
-  nsCString crashReporterPath_temp;
-
-  exePath->GetNativePath(crashReporterPath_temp);
-  crashReporterPath = ToNewCString(crashReporterPath_temp);
+    nsCString crashReporterPath_temp;
+
+    exePath->GetNativePath(crashReporterPath_temp);
+    crashReporterPath = ToNewCString(crashReporterPath_temp);
 #else
-  // On Android, we launch using the application package name
-  // instead of a filename, so use ANDROID_PACKAGE_NAME to do that here.
-  //TODO: don't hardcode org.mozilla here, so other vendors can
-  // ship XUL apps with different package names on Android?
-  nsCString package(ANDROID_PACKAGE_NAME "/.CrashReporter");
-  crashReporterPath = ToNewCString(package);
+    // On Android, we launch using the application package name
+    // instead of a filename, so use ANDROID_PACKAGE_NAME to do that here.
+    nsCString package(ANDROID_PACKAGE_NAME "/.CrashReporter");
+    crashReporterPath = ToNewCString(package);
 #endif
+  }
 
   // get temp path to use for minidump path
 #if defined(XP_WIN32)
   nsString tempPath;
 
   // first figure out buffer size
   int pathLen = GetTempPath(0, NULL);
   if (pathLen == 0)
@@ -773,22 +811,21 @@ nsresult SetExceptionHandler(nsIFile* aX
   char path[PATH_MAX];
   OSStatus status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
   if (status != noErr)
     return NS_ERROR_FAILURE;
 
   tempPath = path;
 
 #elif defined(__ANDROID__)
-  // GeckoAppShell sets this in the environment
+  // GeckoAppShell or Gonk's init.rc sets this in the environment
   const char *tempenv = PR_GetEnv("TMPDIR");
   if (!tempenv)
     return NS_ERROR_FAILURE;
   nsCString tempPath(tempenv);
-
 #elif defined(XP_UNIX)
   // we assume it's always /tmp on unix systems
   nsCString tempPath = NS_LITERAL_CSTRING("/tmp/");
 #else
 #error "Implement this for your platform"
 #endif
 
 #ifdef XP_MACOSX
@@ -892,17 +929,17 @@ nsresult SetExceptionHandler(nsIFile* aX
   Boolean keyExistsAndHasValidFormat = false;
   Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("OSCrashReporter"),
                                                         kCFPreferencesCurrentApplication,
                                                         &keyExistsAndHasValidFormat);
   if (keyExistsAndHasValidFormat)
     showOSCrashReporter = prefValue;
 #endif
 
-#if defined(__ANDROID__)
+#if defined(MOZ_WIDGET_ANDROID)
   for (unsigned int i = 0; i < library_mappings.size(); i++) {
     u_int8_t guid[sizeof(MDGUID)];
     FileIDToGUID(library_mappings[i].debug_id.c_str(), guid);
     gExceptionHandler->AddMappingInfo(library_mappings[i].name,
                                       guid,
                                       library_mappings[i].start_address,
                                       library_mappings[i].length,
                                       library_mappings[i].file_offset);
@@ -1117,16 +1154,44 @@ nsresult SetupExtraData(nsIFile* aAppDat
   nsCAutoString filename;
   rv = lastCrashFile->GetNativePath(filename);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (filename.Length() < XP_PATH_MAX)
     strncpy(lastCrashTimeFilename, filename.get(), filename.Length());
 #endif
 
+  if (headlessClient) {
+    nsCOMPtr<nsIFile> markerFile;
+    rv = dataDirectory->Clone(getter_AddRefs(markerFile));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = markerFile->AppendNative(NS_LITERAL_CSTRING("LastCrashFilename"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    memset(crashMarkerFilename, 0, sizeof(crashMarkerFilename));
+
+#if defined(XP_WIN32)
+    nsAutoString markerFilename;
+    rv = markerFile->GetPath(markerFilename);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (markerFilename.Length() < XP_PATH_MAX)
+      wcsncpy(crashMarkerFilename, markerFilename.get(),
+              markerFilename.Length());
+#else
+    nsCAutoString markerFilename;
+    rv = markerFile->GetNativePath(markerFilename);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (markerFilename.Length() < XP_PATH_MAX)
+      strncpy(crashMarkerFilename, markerFilename.get(),
+              markerFilename.Length());
+#endif
+  }
+
   return NS_OK;
 }
 
 static void OOPDeinit();
 
 nsresult UnsetExceptionHandler()
 {
 #ifdef XP_WIN
@@ -1148,16 +1213,19 @@ nsresult UnsetExceptionHandler()
   notesFieldLock = nsnull;
 
   delete crashReporterAPIData;
   crashReporterAPIData = nsnull;
 
   delete notesField;
   notesField = nsnull;
 
+  delete lastRunCrashID;
+  lastRunCrashID = nsnull;
+
   if (pendingDirectory) {
     NS_Free(pendingDirectory);
     pendingDirectory = nsnull;
   }
 
   if (crashReporterPath) {
     NS_Free(crashReporterPath);
     crashReporterPath = nsnull;
@@ -1508,36 +1576,36 @@ static nsresult PrefSubmitReports(bool* 
 
   nsCAutoString regPath;
 
   regPath.AppendLiteral("Software\\");
 
   // We need to ensure the registry keys are created so we can properly
   // write values to it
   
-  // Create appVendor key
-  if(!appVendor.IsEmpty()) {
-    regPath.Append(appVendor);
-    regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
-                   NS_ConvertUTF8toUTF16(regPath),
-                   nsIWindowsRegKey::ACCESS_SET_VALUE);
-    regPath.AppendLiteral("\\");
-  }
-
-  // Create appName key
-  regPath.Append(appName);
-  regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
-                 NS_ConvertUTF8toUTF16(regPath),
-                 nsIWindowsRegKey::ACCESS_SET_VALUE);
-  regPath.AppendLiteral("\\");
-
-  // Create Crash Reporter key
-  regPath.AppendLiteral("Crash Reporter");
-  regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
-                 NS_ConvertUTF8toUTF16(regPath),
+  // Create appVendor key
+  if(!appVendor.IsEmpty()) {
+    regPath.Append(appVendor);
+    regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+                   NS_ConvertUTF8toUTF16(regPath),
+                   nsIWindowsRegKey::ACCESS_SET_VALUE);
+    regPath.AppendLiteral("\\");
+  }
+
+  // Create appName key
+  regPath.Append(appName);
+  regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+                 NS_ConvertUTF8toUTF16(regPath),
+                 nsIWindowsRegKey::ACCESS_SET_VALUE);
+  regPath.AppendLiteral("\\");
+
+  // Create Crash Reporter key
+  regPath.AppendLiteral("Crash Reporter");
+  regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+                 NS_ConvertUTF8toUTF16(regPath),
                  nsIWindowsRegKey::ACCESS_SET_VALUE);
 
   // If we're saving the pref value, just write it to ROOT_KEY_CURRENT_USER
   // and we're done.
   if (writePref) {
     rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
                       NS_ConvertUTF8toUTF16(regPath),
                       nsIWindowsRegKey::ACCESS_SET_VALUE);
@@ -1690,16 +1758,43 @@ nsresult SetSubmitReports(bool aSubmitRe
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     obsServ->NotifyObservers(nsnull, "submit-reports-pref-changed", nsnull);
     return NS_OK;
 }
 
+static void
+FindPendingDir()
+{
+  if (pendingDirectory)
+    return;
+
+  nsCOMPtr<nsIFile> pendingDir;
+  nsresult rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(pendingDir));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Couldn't get the user appdata directory, crash dumps will go in an unusual location");
+  }
+  else {
+    pendingDir->Append(NS_LITERAL_STRING("Crash Reports"));
+    pendingDir->Append(NS_LITERAL_STRING("pending"));
+
+#ifdef XP_WIN
+    nsString path;
+    pendingDir->GetPath(path);
+    pendingDirectory = ToNewUnicode(path);
+#else
+    nsCString path;
+    pendingDir->GetNativePath(path);
+    pendingDirectory = ToNewCString(path);
+#endif
+  }
+}
+
 // The "pending" dir is Crash Reports/pending, from which minidumps
 // can be submitted. Because this method may be called off the main thread,
 // we store the pending directory as a path.
 static bool
 GetPendingDir(nsIFile** dir)
 {
   MOZ_ASSERT(OOPInitialized());
   if (!pendingDirectory) {
@@ -1939,17 +2034,17 @@ OnChildProcessDumpRequested(void* aConte
   CreateFileFromPath(
 #ifdef XP_MACOSX
                      aFilePath,