Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Wed, 25 Jul 2012 14:30:08 -0700
changeset 106588 d80fbd8493f175eaa24d7b9145f7c6a321b7e8ad
parent 106587 41f66d0e46b3f068a5703995a1a0127a9bff9160 (current diff)
parent 100401 d03aed049b7be26e44157e71b5eb642f8f78224b (diff)
child 106589 81146d7c9f5170c821bc6f517dafd0bcd0635751
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
accessible/src/msaa/DocAccessibleWrap.cpp
b2g/installer/package-manifest.in
browser/app/nsBrowserApp.cpp
browser/app/profile/firefox.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/base/jar.mn
browser/devtools/shared/Require.jsm
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/browser.properties
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
configure.in
content/base/test/Makefile.in
content/base/test/header.sjs
content/base/test/test_header.html
docshell/base/nsDocShell.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/ipc/CrashReporterParent.cpp
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginHost.h
dom/plugins/base/nsPluginTags.cpp
dom/plugins/base/nsPluginTags.h
dom/plugins/ipc/PluginInstanceParent.cpp
editor/libeditor/base/PlaceholderTxn.cpp
editor/libeditor/base/PlaceholderTxn.h
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorUtils.cpp
editor/libeditor/base/nsEditorUtils.h
editor/libeditor/base/nsIAbsorbingTransaction.h
editor/libeditor/base/nsSelectionState.cpp
editor/libeditor/base/nsSelectionState.h
editor/libeditor/html/nsHTMLEditRules.cpp
editor/libeditor/html/nsHTMLEditRules.h
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditorStyle.cpp
editor/libeditor/html/nsTableEditor.cpp
embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
embedding/browser/webBrowser/nsWebBrowser.cpp
extensions/cookie/nsPermissionManager.cpp
gfx/gl/GLContext.h
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/d3d10/LayerManagerD3D10.cpp
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/ipc/ShadowLayersParent.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
intl/uconv/src/nsUTF8ConverterService.cpp
js/src/builtin/ParallelArray.cpp
js/src/config/autoconf.mk.in
js/src/frontend/BytecodeEmitter.cpp
js/src/ion/MIR.cpp
js/src/ion/VMFunctions.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jsbool.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsopcode.h
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jstypedarray.cpp
js/src/jsxml.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/StubCalls.cpp
js/src/vm/Debugger.cpp
js/xpconnect/src/Makefile.in
js/xpconnect/src/XPCJSRuntime.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/crashtests/crashtests.list
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsFrame.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
layout/style/nsComputedDOMStyle.cpp
mobile/android/base/GeckoApp.java
mobile/android/chrome/content/browser.js
netwerk/base/src/nsIOService.cpp
netwerk/base/src/nsProtocolProxyService.cpp
netwerk/mime/nsMIMEHeaderParamImpl.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/test/unit/test_proxy_preservation_bug235853.js
profile/dirserviceprovider/src/nsProfileLock.cpp
res/drawable-hdpi/sync_fx_icon.png
res/drawable-ldpi/sync_fx_icon.png
res/drawable-mdpi/sync_fx_icon.png
toolkit/components/parentalcontrols/nsParentalControlsServiceWin.cpp
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/xre/nsAppRunner.cpp
widget/nsIWidget.h
widget/qt/nsWindow.cpp
widget/windows/JumpListBuilder.cpp
widget/windows/JumpListBuilder.h
widget/windows/JumpListItem.cpp
widget/windows/JumpListItem.h
widget/windows/nsDataObj.cpp
widget/windows/nsDataObj.h
widget/windows/nsFilePicker.cpp
widget/windows/nsWindow.cpp
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
xpfe/appshell/src/nsChromeTreeOwner.cpp
xpfe/appshell/src/nsContentTreeOwner.cpp
xpfe/appshell/src/nsXULWindow.cpp
--- 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) {
@@ -524,21 +583,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
@@ -103,16 +103,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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..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/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1209,19 +1209,20 @@
             // if we're adding tabs, we're past interrupt mode, ditch the owner
             if (this.mCurrentTab.owner)
               this.mCurrentTab.owner = null;
 
             var t = document.createElementNS(
               "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                                              "tab");
 
-            var blank = !aURI || (aURI == "about:blank");
-
-            if (blank)
+            var uriIsBlankPage = !aURI || isBlankPageURL(aURI);
+            var uriIsNotAboutBlank = aURI && aURI != "about:blank";
+
+            if (uriIsBlankPage)
               t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
             else
               t.setAttribute("label", aURI);
 
             t.setAttribute("crop", "end");
             t.setAttribute("validate", "never");
             t.setAttribute("onerror", "this.removeAttribute('image');");
             t.className = "tabbrowser-tab";
@@ -1323,18 +1324,25 @@
             // browser element, which fires off a bunch of notifications. Some
             // of those notifications can cause code to run that inspects our
             // state, so it is important that the tab element is fully
             // initialized by this point.
             this.mPanelContainer.appendChild(notificationbox);
 
             this.tabContainer.updateVisibility();
 
+            if (uriIsNotAboutBlank) {
+              // Stop the existing about:blank load.  Otherwise, if aURI
+              // doesn't stop in-progress loads on its own, we'll get into
+              // trouble with multiple parallel loads running at once.
+              b.stop();
+            }
+
             // wire up a progress listener for the new browser object.
-            var tabListener = this.mTabProgressListener(t, b, blank);
+            var tabListener = this.mTabProgressListener(t, b, uriIsBlankPage);
             const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
                                      .createInstance(Components.interfaces.nsIWebProgress);
             filter.addProgressListener(tabListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
 #ifdef MOZ_E10S_COMPAT
             // Bug 666801 - WebProgress support for e10s
 #else
             b.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
 #endif
@@ -1346,25 +1354,20 @@
 
             // Dispatch a new tab notification.  We do this once we're
             // entirely done, so that things are in a consistent state
             // even if the event listener opens or closes tabs.
             var evt = document.createEvent("Events");
             evt.initEvent("TabOpen", true, false);
             t.dispatchEvent(evt);
 
-            if (!blank) {
-              // Stop the existing about:blank load.  Otherwise, if aURI
-              // doesn't stop in-progress loads on its own, we'll get into
-              // trouble with multiple parallel loads running at once.
-              b.stop();
-
+            if (uriIsNotAboutBlank) {
               // pretend the user typed this so it'll be available till
               // the document successfully loads
-              if (!isBlankPageURL(aURI))
+              if (!uriIsBlankPage)
                 b.userTypedValue = aURI;
 
               let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
               if (aAllowThirdPartyFixup)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
               if (aFromExternal)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
               if (aIsUTF8)
--- 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/devtools/commandline/gcli.jsm
+++ b/browser/devtools/commandline/gcli.jsm
@@ -21,17 +21,17 @@
  * This file is generated from separate files stored in the GCLI project.
  * Please modify the files there and use the import script so the 2 projects
  * are kept in sync.
  * For more information, ask Joe Walker <jwalker@mozilla.com>
  */
 
 var EXPORTED_SYMBOLS = [ "gcli" ];
 
-Components.utils.import("resource:///modules/devtools/Require.jsm");
+Components.utils.import("resource://gre/modules/Require.jsm");
 Components.utils.import("resource:///modules/devtools/Console.jsm");
 Components.utils.import("resource:///modules/devtools/Browser.jsm");
 
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
--- a/browser/devtools/commandline/test/browser_gcli_integrate.js
+++ b/browser/devtools/commandline/test/browser_gcli_integrate.js
@@ -6,17 +6,17 @@
 
 function test() {
   testCreateCommands();
   testRemoveCommands();
 }
 
 let [ define, require ] = (function() {
   let tempScope = {};
-  Components.utils.import("resource:///modules/devtools/Require.jsm", tempScope);
+  Components.utils.import("resource://gre/modules/Require.jsm", tempScope);
   return [ tempScope.define, tempScope.require ];
 })();
 
 registerCleanupFunction(function tearDown() {
   define = undefined;
   require = undefined;
 });
 
--- a/browser/devtools/commandline/test/browser_gcli_pref.js
+++ b/browser/devtools/commandline/test/browser_gcli_pref.js
@@ -37,17 +37,17 @@ function test() {
   });
 }
 
 let tiltEnabledOrig = undefined;
 let tabSizeOrig = undefined;
 let remoteHostOrig = undefined;
 
 function setup() {
-  Components.utils.import("resource:///modules/devtools/Require.jsm", imports);
+  Components.utils.import("resource://gre/modules/Require.jsm", imports);
   imports.settings = imports.require("gcli/settings");
 
   tiltEnabledOrig = imports.prefBranch.getBoolPref("devtools.tilt.enabled");
   tabSizeOrig = imports.prefBranch.getIntPref("devtools.editor.tabsize");
   remoteHostOrig = imports.prefBranch.getComplexValue(
           "devtools.debugger.remote-host",
           Components.interfaces.nsISupportsString).data;
 
--- a/browser/devtools/commandline/test/browser_gcli_settings.js
+++ b/browser/devtools/commandline/test/browser_gcli_settings.js
@@ -36,17 +36,17 @@ let tiltEnabled = undefined;
 let tabSize = undefined;
 let remoteHost = undefined;
 
 let tiltEnabledOrig = undefined;
 let tabSizeOrig = undefined;
 let remoteHostOrig = undefined;
 
 function setup() {
-  Components.utils.import("resource:///modules/devtools/Require.jsm", imports);
+  Components.utils.import("resource://gre/modules/Require.jsm", imports);
   imports.settings = imports.require("gcli/settings");
 
   tiltEnabled = imports.settings.getSetting("devtools.tilt.enabled");
   tabSize = imports.settings.getSetting("devtools.editor.tabsize");
   remoteHost = imports.settings.getSetting("devtools.debugger.remote-host");
 
   tiltEnabledOrig = imports.prefBranch.getBoolPref("devtools.tilt.enabled");
   tabSizeOrig = imports.prefBranch.getIntPref("devtools.editor.tabsize");
--- a/browser/devtools/commandline/test/browser_gcli_web.js
+++ b/browser/devtools/commandline/test/browser_gcli_web.js
@@ -49,17 +49,17 @@
  *
  *
  */
 
 ///////////////////////////////////////////////////////////////////////////////
 
 let [ define, require ] = (function() {
   let tempScope = {};
-  Components.utils.import("resource:///modules/devtools/Require.jsm", tempScope);
+  Components.utils.import("resource://gre/modules/Require.jsm", tempScope);
   return [ tempScope.define, tempScope.require ];
 })();
 
 let console = (function() {
   let tempScope = {};
   Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
   return console;
 })();
--- a/browser/devtools/shared/test/browser_require_basic.js
+++ b/browser/devtools/shared/test/browser_require_basic.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that source URLs in the Web Console can be clicked to display the
 // standard View Source window.
 
 let [ define, require ] = (function() {
   let tempScope = {};
-  Components.utils.import("resource:///modules/devtools/Require.jsm", tempScope);
+  Components.utils.import("resource://gre/modules/Require.jsm", tempScope);
   return [ tempScope.define, tempScope.require ];
 })();
 
 function test() {
   addTab("about:blank", function() {
     info("Starting Require Tests");
     setup();
 
--- 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/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
@@ -5968,16 +5968,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/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/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/ParallelArray.cpp
+++ b/js/src/builtin/ParallelArray.cpp
@@ -390,17 +390,17 @@ ParallelArray_filter_impl(JSContext *cx,
         frame.setCallee(ObjectValue(*elementalFun));
         frame[0].setNumber(i);
         frame.thisv() = ObjectValue(*obj);
 
         /* call */
         if (!Invoke(cx, frame))
             return false;
 
-        if (js_ValueToBoolean(frame.rval()))
+        if (ToBoolean(frame.rval()))
             resBuffer->setDenseArrayElementWithType(cx, pos++, buffer->getDenseArrayElement(i));
     }
 
     /* shrink the array to the proper size */
     resBuffer->setArrayLength(cx, pos);
 
     /* create ParallelArray wrapper class */
     RootedObject result(cx, NewParallelArray(cx, resBuffer, pos));
--- 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 {
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -1360,17 +1360,17 @@ MCompare::foldsTo(bool useValueNumbers)
 
 MDefinition *
 MNot::foldsTo(bool useValueNumbers)
 {
     // Fold if the input is constant
     if (operand()->isConstant()) {
        const Value &v = operand()->toConstant()->value();
         // ValueToBoolean can cause no side-effects, so this is safe.
-        return MConstant::New(BooleanValue(!js_ValueToBoolean(v)));
+        return MConstant::New(BooleanValue(!ToBoolean(v)));
     }
 
     // NOT of an object is always false
     if (operand()->type() == MIRType_Object)
         return MConstant::New(BooleanValue(false));
 
     // NOT of an undefined or null value is always true
     if (operand()->type() == MIRType_Undefined || operand()->type() == MIRType_Null)
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -210,17 +210,17 @@ StringsEqual(JSContext *cx, HandleString
 }
 
 template bool StringsEqual<true>(JSContext *cx, HandleString lhs, HandleString rhs, JSBool *res);
 template bool StringsEqual<false>(JSContext *cx, HandleString lhs, HandleString rhs, JSBool *res);
 
 bool
 ValueToBooleanComplement(JSContext *cx, const Value &input, JSBool *output)
 {
-    *output = !js_ValueToBoolean(input);
+    *output = !ToBoolean(input);
     return true;
 }
 
 bool
 IteratorMore(JSContext *cx, HandleObject obj, JSBool *res)
 {
     Value tmp;
     if (!js_IteratorMore(cx, obj, &tmp))
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
@@ -322,17 +322,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;
@@ -480,17 +480,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;
       }
@@ -632,17 +632,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);
@@ -5359,39 +5359,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
@@ -2660,16 +2660,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)
 {
@@ -2678,16 +2684,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
@@ -540,17 +540,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;
@@ -587,93 +587,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
@@ -699,29 +708,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();
 }
 
@@ -733,21 +742,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
@@ -899,20 +899,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
@@ -739,17 +739,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
@@ -505,16 +505,18 @@ IsSetterPC(jsbytecode *pc)
  * 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,
 
@@ -623,16 +625,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);
+
 static inline jsbytecode *
 GetNextPc(jsbytecode *pc)
 {
     return pc + js_CodeSpec[JSOp(*pc)].length;
 }
 
 } /* namespace js */
 
--- 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
@@ -353,16 +353,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;
@@ -521,16 +522,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))
@@ -602,16 +605,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)) {
@@ -844,16 +849,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);
     }
@@ -1173,21 +1179,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;
@@ -1810,16 +1818,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))
@@ -2289,16 +2298,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
@@ -542,16 +542,17 @@ struct JSScript : public js::gc::Cell
     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            invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */
     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
@@ -2372,17 +2372,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)
 {
@@ -2428,17 +2428,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
@@ -447,23 +447,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.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/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 fr