merge from mozilla-central
authorBrad Lassey <blassey@mozilla.com>
Sat, 18 Feb 2012 17:29:33 -0500
changeset 89198 9b757be291639d5baad2dd859a13db990278e8d4
parent 89196 52b69194d8f62b4457d1365054484cdb91d8e7ed (current diff)
parent 87196 e06ab2cf18b88511abdcefbc94eea743d6e3391d (diff)
child 89199 1705e50937fc9cb1344ed3272e14a00636b08730
push id7119
push usereakhgari@mozilla.com
push dateWed, 14 Mar 2012 17:40:57 +0000
treeherdermozilla-inbound@10d7baa4aff0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.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
dom/bluetooth/BluetoothAdapter.cpp
dom/bluetooth/BluetoothAdapter.h
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/Makefile.in
dom/bluetooth/nsIDOMBluetoothAdapter.idl
dom/bluetooth/nsIDOMNavigatorBluetooth.idl
dom/workers/test/fileMozSlice_worker.js
dom/workers/test/fileReadMozSlice_worker.js
dom/workers/test/test_fileMozSlice.xul
dom/workers/test/test_fileReadMozSlice.xul
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
layout/generic/nsGfxScrollFrame.cpp
media/libjpeg/cderror.h
media/libjpeg/cdjpeg.h
media/libjpeg/jconfig.h.in
media/libjpeg/simd/jsimdcfg.inc.h
media/libjpeg/transupp.h
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/sync/crypto/Cryptographer.java
mobile/android/base/sync/cryptographer/CryptoStatusBundle.java
mobile/android/base/sync/cryptographer/SyncCryptographer.java
mobile/android/base/sync/jpake/Gx4IsOneException.java
mobile/android/base/sync/jpake/JPakeUtils.java
mobile/android/chrome/content/browser.js
modules/libpref/src/init/all.js
security/patches/bug-717906-lowhash
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
widget/nsIWidget.h
widget/xpwidgets/nsBaseWidget.h
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -1489,38 +1489,34 @@ nsHTMLTableAccessible::IsProbablyForLayo
   if (border.top && border.bottom && border.left && border.right) {
     RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
   }
 
   /**
    * Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward
    */
 
-  // Check for styled background color across the row
-  // Alternating background color is a common way 
-  nsCOMPtr<nsIDOMNodeList> nodeList;
-  nsCOMPtr<nsIDOMElement> tableElt(do_QueryInterface(mContent));    
-  tableElt->GetElementsByTagName(NS_LITERAL_STRING("tr"), getter_AddRefs(nodeList));
-  NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
-  PRUint32 length;
-  nodeList->GetLength(&length);
-  nsAutoString color, lastRowColor;
-  for (PRUint32 rowCount = 0; rowCount < length; rowCount ++) {
-    nsCOMPtr<nsIDOMNode> rowNode;
-    nodeList->Item(rowCount, getter_AddRefs(rowNode));
-    nsCOMPtr<nsIContent> rowContent(do_QueryInterface(rowNode));
-
-    nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
-      nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), rowContent);
-    NS_ENSURE_TRUE(styleDecl, NS_ERROR_FAILURE);
-
-    lastRowColor = color;
-    styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"), color);
-    if (rowCount > 0 && false == lastRowColor.Equals(color)) {
-      RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
+  // Check for styled background color across rows (alternating background
+  // color is a common feature for data tables).
+  PRUint32 childCount = GetChildCount();
+  nsAutoString rowColor, prevRowColor;
+  for (PRUint32 childIdx = 0; childIdx < childCount; childIdx++) {
+    nsAccessible* child = GetChildAt(childIdx);
+    if (child->Role() == roles::ROW) {
+      nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
+        nsCoreUtils::GetComputedStyleDeclaration(EmptyString(),
+                                                 child->GetContent());
+      if (styleDecl) {
+        prevRowColor = rowColor;
+        styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"),
+                                    rowColor);
+        if (childIdx > 0 && !prevRowColor.Equals(rowColor)) {
+          RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
+        }
+      }
     }
   }
 
   // Check for many rows
   const PRInt32 kMaxLayoutRows = 20;
   if (rows > kMaxLayoutRows) { // A ton of rows, this is probably for data
     RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
   }
--- a/accessible/tests/mochitest/treeupdate/Makefile.in
+++ b/accessible/tests/mochitest/treeupdate/Makefile.in
@@ -43,16 +43,17 @@ VPATH		= @srcdir@
 relativesrcdir  = accessible/treeupdate
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		test_ariadialog.html \
 		test_colorpicker.xul \
+		test_cssoverflow.html \
 		test_contextmenu.xul \
 		test_doc.html \
 		test_gencontent.html \
 		test_list_editabledoc.html \
 		test_list.html \
 		test_menu.xul \
 		test_menubutton.xul \
 		test_recreation.html \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_cssoverflow.html
@@ -0,0 +1,141 @@
+<html>
+
+<head>
+  <title>Testing HTML scrollable frames (css overflow style)</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Change scroll range to not empty size and inserts a child into container
+     * to trigger tree update of the container. Prior to bug 677154 not empty
+     * size resulted to accessible creation for scroll area, container tree
+     * update picked up that accessible unattaching scroll area accessible
+     * subtree.
+     */
+    function changeScrollRange(aContainerID, aScrollAreaID)
+    {
+      this.containerNode = getNode(aContainerID);
+      this.container = getAccessible(this.containerNode);
+      this.scrollAreaNode = getNode(aScrollAreaID);
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, this.container)
+      ];
+
+      this.invoke = function changeScrollRange_invoke()
+      {
+        this.scrollAreaNode.style.width = "20px";
+        this.containerNode.appendChild(document.createElement("input"));
+      }
+
+      this.finalCheck = function changeScrollRange_finalCheck()
+      {
+        var accTree =
+          { SECTION: [ // container
+            { SECTION: [ // scroll area
+              { ENTRY: [] } // child content
+            ] },
+            { ENTRY: [] } // inserted input
+          ] };
+        testAccessibleTree(this.container, accTree);
+      }
+
+      this.getID = function changeScrollRange_getID()
+      {
+        return "change scroll range for " + prettyName(aScrollAreaID);
+      }
+    }
+
+    /**
+     * Change scrollbar styles from hidden to auto. That makes us to create an
+     * accessible for scroll area.
+     */
+    function changeScrollbarStyles(aContainerID, aScrollAreaID)
+    {
+      this.container = getAccessible(aContainerID);
+      this.scrollAreaNode = getNode(aScrollAreaID);
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, getAccessible, this.scrollAreaNode),
+        new invokerChecker(EVENT_REORDER, this.container)
+      ];
+
+      this.invoke = function changeScrollbarStyles_invoke()
+      {
+        var accTree =
+          { SECTION: [] };
+        testAccessibleTree(this.container, accTree);
+
+        this.scrollAreaNode.style.overflow = "auto";
+      }
+
+      this.finalCheck = function changeScrollbarStyles_finalCheck()
+      {
+        var accTree =
+          { SECTION: [ // container
+            { SECTION: [] } // scroll area
+          ] };
+        testAccessibleTree(this.container, accTree);
+      }
+
+      this.getID = function changeScrollbarStyles_getID()
+      {
+        return "change scrollbar styles " + prettyName(aScrollAreaID);
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Do tests
+    ////////////////////////////////////////////////////////////////////////////
+
+    var gQueue = null;
+    //gA11yEventDumpID = "eventdump"; // debug stuff
+    //gA11yEventDumpToConsole = true;
+
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new changeScrollRange("container", "scrollarea"));
+      gQueue.push(new changeScrollbarStyles("container2", "scrollarea2"));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=677154"
+     title="Detached document accessibility tree">
+    Mozilla Bug 677154</a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+  <div id="eventdump"></div>
+
+  <div id="container"><div id="scrollarea" style="overflow:auto;"><input></div></div>
+  <div id="container2"><div id="scrollarea2" style="overflow:hidden;"></div></div>
+</body>
+</html>
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -12,16 +12,17 @@ builtin(include, build/autoconf/codeset.
 builtin(include, build/autoconf/altoptions.m4)dnl
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/mozcommonheader.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
 builtin(include, build/autoconf/gcc-pr49911.m4)dnl
 builtin(include, build/autoconf/frameptr.m4)dnl
+builtin(include, build/autoconf/compiler-opts.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
 
 # Read the user's .mozconfig script.  We can't do this in
 # configure.in: autoconf puts the argument parsing code above anything
 # expanded from configure.in, and we need to get the configure options
 # from .mozconfig in place before that argument parsing code.
 MOZ_READ_MOZCONFIG(.)
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -421,12 +421,18 @@ pref("media.realtime_decoder.enabled", t
 // of talos regression.  This is a needed change for higher-framerate
 // CSS animations, and incidentally works around an apparent bug in
 // our handling of requestAnimationFrame() listeners, which are
 // supposed to enable this REPEATING_PRECISE_CAN_SKIP behavior.  The
 // secondary bug isn't really worth investigating since it's obseleted
 // by bug 710563.
 pref("layout.frame_rate.precise", true);
 
+// Temporary remote js console hack
+pref("b2g.remote-js.enabled", true);
+pref("b2g.remote-js.port", 9999);
+
 // Screen timeout in minutes
 pref("power.screen.timeout", 60);
 
 pref("full-screen-api.enabled", true);
+
+pref("media.volume.steps", 10);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const CC = Components.Constructor;
+const Cr = Components.results;
 
 const LocalFile = CC('@mozilla.org/file/local;1',
                      'nsILocalFile',
                      'initWithPath');
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
 
@@ -20,21 +21,28 @@ XPCOMUtils.defineLazyGetter(Services, 'e
   return Cc['@mozilla.org/process/environment;1']
            .getService(Ci.nsIEnvironment);
 });
 
 XPCOMUtils.defineLazyGetter(Services, 'ss', function() {
   return Cc['@mozilla.org/content/style-sheet-service;1']
            .getService(Ci.nsIStyleSheetService);
 });
+
 XPCOMUtils.defineLazyGetter(Services, 'idle', function() {
   return Cc['@mozilla.org/widget/idleservice;1']
            .getService(Ci.nsIIdleService);
 });
 
+XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function(){
+  return Cc['@mozilla.org/focus-managr;1']
+           .getService(Ci.nsFocusManager);
+});
+
+
 // In order to use http:// scheme instead of file:// scheme
 // (that is much more restricted) the following code kick-off
 // a local http server listening on http://127.0.0.1:7777 and
 // http://localhost:7777.
 function startupHttpd(baseDir, port) {
   const httpdURL = 'chrome://browser/content/httpd.js';
   let httpd = {};
   Services.scriptloader.loadSubScript(httpdURL, httpd);
@@ -100,16 +108,17 @@ var shell = {
       let msg = 'Fatal error during startup: [No homescreen found]';
       return alert(msg);
     }
 
     window.controllers.appendController(this);
     window.addEventListener('keypress', this);
     window.addEventListener('MozApplicationManifest', this);
     window.addEventListener("AppCommand", this);
+    window.addEventListener('mozfullscreenchange', this);
     this.contentBrowser.addEventListener('load', this, true);
 
     try {
       Services.io.offline = false;
 
       let fileScheme = 'file://';
       if (homeURL.substring(0, fileScheme.length) == fileScheme) {
         homeURL = homeURL.replace(fileScheme, '');
@@ -181,16 +190,34 @@ var shell = {
     if (this.isDebug) {
       Services.prefs.setBoolPref("layers.acceleration.draw-fps", true);
       Services.prefs.setBoolPref("nglayout.debug.paint_flashing", true);
     } else {
       Services.prefs.setBoolPref("layers.acceleration.draw-fps", false);
       Services.prefs.setBoolPref("nglayout.debug.paint_flashing", false);
     }
   },
+ 
+  changeVolume: function shell_changeVolume(aDelta) {
+    let audioManager = Cc["@mozilla.org/telephony/audiomanager;1"].getService(Ci.nsIAudioManager);
+
+    let steps = 10;
+    try {
+      steps = Services.prefs.getIntPref("media.volume.steps");
+      if (steps <= 0)
+        steps = 1;
+    } catch(e) {}
+
+    let volume = audioManager.masterVolume + aDelta / steps;
+    if (volume > 1)
+      volume = 1;
+    if (volume < 0)
+      volume = 0;
+    audioManager.masterVolume = volume;
+  },
 
   handleEvent: function shell_handleEvent(evt) {
     switch (evt.type) {
       case 'keypress':
         switch (evt.keyCode) {
           case evt.DOM_VK_HOME:
             this.sendEvent(content, 'home');
             break;
@@ -212,18 +239,32 @@ var shell = {
       case 'AppCommand':
         switch (evt.command) {
           case 'Menu':
             this.sendEvent(content, 'menu');
             break;
           case 'Search':
             this.toggleDebug();
             break;
+          case 'VolumeUp':
+            this.changeVolume(1);
+            break;
+          case 'VolumeDown':
+            this.changeVolume(-1);
+            break;
         }
         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 'load':
         this.contentBrowser.removeEventListener('load', this, true);
         this.turnScreenOn();
 
         let chromeWindow = window.QueryInterface(Ci.nsIDOMChromeWindow);
         chromeWindow.browserDOMWindow = new nsBrowserAccess();
 
         this.sendEvent(window, 'ContentStart');
@@ -334,8 +375,55 @@ nsBrowserAccess.prototype = {
 // to logcat.
 Services.obs.addObserver(function onConsoleAPILogEvent(subject, topic, data) {
   let message = subject.wrappedJSObject;
   let prefix = "Content JS " + message.level.toUpperCase() +
                " at " + message.filename + ":" + message.lineNumber +
                " in " + (message.functionName || "anonymous") + ": ";
   Services.console.logStringMessage(prefix + Array.join(message.arguments, " "));
 }, "console-api-log-event", false);
+
+(function Repl() {
+  if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) {
+    return;
+  }
+  const prompt = 'JS> ';
+  let output;
+  let reader = {
+    onInputStreamReady : function repl_readInput(input) {
+      let sin = Cc['@mozilla.org/scriptableinputstream;1']
+                  .createInstance(Ci.nsIScriptableInputStream);
+      sin.init(input);
+      try {
+        let val = eval(sin.read(sin.available()));
+        let ret = (typeof val === 'undefined') ? 'undefined\n' : val + '\n';
+        output.write(ret, ret.length);
+        // TODO: check if socket has been closed
+      } catch (e) {
+        if (e.result === Cr.NS_BASE_STREAM_CLOSED ||
+            (typeof e === 'object' && e.result === Cr.NS_BASE_STREAM_CLOSED)) {
+          return;
+        }
+        let message = (typeof e === 'object') ? e.message + '\n' : e + '\n';
+        output.write(message, message.length);
+      }
+      output.write(prompt, prompt.length);
+      input.asyncWait(reader, 0, 0, Services.tm.mainThread);
+    }
+  }
+  let listener = {
+    onSocketAccepted: function repl_acceptConnection(serverSocket, clientSocket) {
+      dump('Accepted connection on ' + clientSocket.host + '\n');
+      let input = clientSocket.openInputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0)
+                              .QueryInterface(Ci.nsIAsyncInputStream);
+      output = clientSocket.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
+      output.write(prompt, prompt.length);
+      input.asyncWait(reader, 0, 0, Services.tm.mainThread);
+    }
+  }
+  let serverPort = Services.prefs.getIntPref('b2g.remote-js.port');
+  let serverSocket = Cc['@mozilla.org/network/server-socket;1']
+                       .createInstance(Ci.nsIServerSocket);
+  serverSocket.init(serverPort, true, -1);
+  dump('Opened socket on ' + serverSocket.port + '\n');
+  serverSocket.asyncListen(listener);
+})();
+
--- a/b2g/chrome/content/webapi.js
+++ b/b2g/chrome/content/webapi.js
@@ -172,89 +172,82 @@ const ContentPanning = {
       case 'click':
         evt.stopPropagation();
         evt.preventDefault();
         evt.target.removeEventListener('click', this, true);
         break;
     }
   },
 
-  position: {
-    origin: new Point(0, 0),
-    current: new Point(0 , 0)
-  },
+  position: new Point(0 , 0),
 
   onTouchStart: function cp_onTouchStart(evt) {
     this.dragging = true;
-    KineticPanning.stop();
+
+    // If there is a pan animation running (from a previous pan gesture) and
+    // the user touch back the screen, stop this animation immediatly and
+    // prevent the possible click action.
+    if (KineticPanning.active) {
+      KineticPanning.stop();
+      this.preventNextClick = true;
+    }
 
     this.scrollCallback = this.getPannable(evt.originalTarget);
-    this.position.origin.set(evt.screenX, evt.screenY);
-    this.position.current.set(evt.screenX, evt.screenY);
-    KineticPanning.record(new Point(0, 0));
+    this.position.set(evt.screenX, evt.screenY);
+    KineticPanning.record(new Point(0, 0), evt.timeStamp);
   },
 
   onTouchEnd: function cp_onTouchEnd(evt) {
     if (!this.dragging)
       return;
     this.dragging = false;
 
-    if (this.isPan()) {
-      if (evt.detail) // The event will generate a click
-        evt.target.addEventListener('click', this, true);
+    this.onTouchMove(evt);
 
+    let pan = KineticPanning.isPan();
+    let click = evt.detail;
+    if (click && (pan || this.preventNextClick))
+      evt.target.addEventListener('click', this, true);
+
+    this.preventNextClick = false;
+
+    if (pan)
       KineticPanning.start(this);
-    }
   },
 
   onTouchMove: function cp_onTouchMove(evt) {
     if (!this.dragging || !this.scrollCallback)
       return;
 
-    let current = this.position.current;
+    let current = this.position;
     let delta = new Point(evt.screenX - current.x, evt.screenY - current.y);
     current.set(evt.screenX, evt.screenY);
 
-    if (this.isPan()) {
-      KineticPanning.record(delta);
-      this.scrollCallback(delta.scale(-1));
-    }
+    KineticPanning.record(delta, evt.timeStamp);
+    this.scrollCallback(delta.scale(-1));
   },
 
 
   onKineticBegin: function cp_onKineticBegin(evt) {
   },
 
   onKineticPan: function cp_onKineticPan(delta) {
     return !this.scrollCallback(delta);
   },
 
   onKineticEnd: function cp_onKineticEnd() {
     if (!this.dragging)
       this.scrollCallback = null;
   },
 
-  isPan: function cp_isPan() {
-    let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDOMWindowUtils)
-                     .displayDPI;
-
-    let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
-
-    let deltaX = this.position.origin.x - this.position.current.x;
-    let deltaY = this.position.origin.y - this.position.current.y;
-    return (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold);
-  },
-
   getPannable: function cp_getPannable(node) {
     if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML')
       return null;
 
     let content = node.ownerDocument.defaultView;
-
     while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) {
       let style = content.getComputedStyle(node, null);
 
       let overflow = [style.getPropertyValue('overflow'),
                       style.getPropertyValue('overflow-x'),
                       style.getPropertyValue('overflow-y')];
 
       let rect = node.getBoundingClientRect();
@@ -294,35 +287,43 @@ const ContentPanning = {
 ContentPanning.init();
 
 
 // Min/max velocity of kinetic panning. This is in pixels/millisecond.
 const kMinVelocity = 0.4;
 const kMaxVelocity = 6;
 
 // Constants that affect the "friction" of the scroll pane.
-const kExponentialC = 1400;
+const kExponentialC = 1000;
 const kPolynomialC = 100 / 1000000;
 
 // How often do we change the position of the scroll pane?
 // Too often and panning may jerk near the end.
 // Too little and panning will be choppy. In milliseconds.
 const kUpdateInterval = 16;
 
+// The numbers of momentums to use for calculating the velocity of the pan.
+// Those are taken from the end of the action
+const kSamples = 5;
+
 const KineticPanning = {
   _position: new Point(0, 0),
   _velocity: new Point(0, 0),
   _acceleration: new Point(0, 0),
 
+  get active() {
+    return this.target !== null;
+  },
+
   _target: null,
   start: function kp_start(target) {
     this.target = target;
 
     // Calculate the initial velocity of the movement based on user input
-    let momentums = this.momentums;
+    let momentums = this.momentums.slice(-kSamples);
 
     let distance = new Point(0, 0);
     momentums.forEach(function(momentum) {
       distance.add(momentum.dx, momentum.dy);
     });
 
     let elapsed = momentums[momentums.length - 1].time - momentums[0].time;
 
@@ -333,16 +334,17 @@ const KineticPanning = {
     }
 
     let velocityX = clampFromZero(distance.x / elapsed, 0, kMaxVelocity);
     let velocityY = clampFromZero(distance.y / elapsed, 0, kMaxVelocity);
 
     let velocity = this._velocity;
     velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX,
                  Math.abs(velocityY) < kMinVelocity ? 0 : velocityY);
+    this.momentums = [];
 
     // Set acceleration vector to opposite signs of velocity
     function sign(x) {
       return x ? (x > 0 ? 1 : -1) : 0;
     }
 
     this._acceleration.set(velocity.clone().map(sign).scale(-kPolynomialC));
 
@@ -353,30 +355,42 @@ const KineticPanning = {
 
     this.target.onKineticBegin();
   },
 
   stop: function kp_stop() {
     if (!this.target)
       return;
 
-    this.momentums.splice(0);
+    this.momentums = [];
 
     this.target.onKineticEnd();
     this.target = null;
   },
 
   momentums: [],
-  record: function kp_record(delta) {
-    // If the panning direction has changed, stop the current activity.
-    if (this.target && ((delta.x * this._velocity.x < 0) ||
-                        (delta.y * this._velocity.y < 0)))
-      this.stop();
+  record: function kp_record(delta, timestamp) {
+    this.momentums.push({ 'time': timestamp, 'dx' : delta.x, 'dy' : delta.y });
+  },
+
+  isPan: function cp_isPan() {
+    let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                     .getInterface(Ci.nsIDOMWindowUtils)
+                     .displayDPI;
 
-    this.momentums.push({ 'time': Date.now(), 'dx' : delta.x, 'dy' : delta.y });
+    let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
+
+    let deltaX = 0;
+    let deltaY = 0;
+    let start = this.momentums[0].time;
+    return this.momentums.slice(1).some(function(momentum) {
+      deltaX += momentum.dx;
+      deltaY += momentum.dy;
+      return (Math.abs(deltaX) > threshold) || (Math.abs(deltaY) > threshold);
+    });
   },
 
   _startAnimation: function kp_startAnimation() {
     let c = kExponentialC;
     function getNextPosition(position, v, a, t) {
       // Important traits for this function:
       //   p(t=0) is 0
       //   p'(t=0) is v0
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -146,19 +146,16 @@
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
-#ifdef MOZ_B2G_BT
-@BINPATH@/components/dom_bluetooth.xpt
-#endif
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1328822681000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1329176667000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -22,18 +22,22 @@
                           </targetApplication>
                     </versionRange>
                                 <versionRange  minVersion="3.3.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="5.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i19" id="{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}">
-                        <versionRange  minVersion="1.1b1" maxVersion="1.1b1">
+      <emItem  blockID="i65" id="activity@facebook.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i66" id="youtubeer@youtuber.com">
+                        <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i54" id="applebeegifts@mozilla.doslash.org">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i16" id="{27182e60-b5f3-411c-b545-b44205977502}">
                         <versionRange  minVersion="1.0" maxVersion="1.0">
@@ -117,18 +121,21 @@
                               <versionRange  minVersion="9.0a1" maxVersion="9.0" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i60" id="youtb3@youtb3.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i56" id="flash@adobe.com">
-                        <versionRange  minVersion="0" maxVersion="*">
+      <emItem  blockID="i23" id="firefox@bandoo.com">
+                        <versionRange  minVersion="5.0" maxVersion="5.0" severity="1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.7a1pre" maxVersion="*" />
+                          </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i55" id="youtube@youtube7.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i11" id="yslow@yahoo-inc.com">
                         <versionRange  minVersion="2.0.5" maxVersion="2.0.5">
@@ -173,30 +180,31 @@
       <emItem  blockID="i62" id="jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
                         <versionRange  minVersion="2.2" maxVersion="2.2">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i23" id="firefox@bandoo.com">
-                        <versionRange  minVersion="5.0" maxVersion="5.0" severity="1">
-                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="3.7a1pre" maxVersion="*" />
-                          </targetApplication>
+      <emItem  blockID="i56" id="flash@adobe.com">
+                        <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i45" id="{22119944-ED35-4ab1-910B-E619EA06A115}">
                         <versionRange  minVersion="0.1" maxVersion="7.6.1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="8.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i19" id="{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}">
+                        <versionRange  minVersion="1.1b1" maxVersion="1.1b1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i3" id="langpack-vi-VN@firefox.mozilla.org">
                         <versionRange  minVersion="2.0" maxVersion="2.0">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
                         </emItem>
       <emItem  blockID="i52" id="ff-ext@youtube">
                         <versionRange  minVersion="0" maxVersion="*">
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -277,16 +277,17 @@ pref("browser.urlbar.clickSelectsAll", f
 pref("browser.urlbar.clickSelectsAll", true);
 #endif
 #ifdef UNIX_BUT_NOT_MAC
 pref("browser.urlbar.doubleClickSelectsAll", true);
 #else
 pref("browser.urlbar.doubleClickSelectsAll", false);
 #endif
 pref("browser.urlbar.autoFill", false);
+pref("browser.urlbar.autoFill.typed", true);
 // 0: Match anywhere (e.g., middle of words)
 // 1: Match on word boundaries and then try matching anywhere
 // 2: Match only on word boundaries (e.g., after / or .)
 // 3: Match at the beginning of the url or title
 pref("browser.urlbar.matchBehavior", 1);
 pref("browser.urlbar.filter.javascript", true);
 
 // the maximum number of results to show in autocomplete when doing richResults
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -9048,38 +9048,54 @@ var Scratchpad = {
 XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() {
   let tmp = {};
   Cu.import("resource:///modules/devtools/scratchpad-manager.jsm", tmp);
   return tmp.ScratchpadManager;
 });
 
 var StyleEditor = {
   prefEnabledName: "devtools.styleeditor.enabled",
-  openChrome: function SE_openChrome()
+  /**
+   * Opens the style editor. If the UI is already open, it will be focused.
+   *
+   * @param {CSSStyleSheet} [aSelectedStyleSheet] default Stylesheet.
+   * @param {Number} [aLine] Line to which the caret should be moved (one-indexed).
+   * @param {Number} [aCol] Column to which the caret should be moved (one-indexed).
+   */
+  openChrome: function SE_openChrome(aSelectedStyleSheet, aLine, aCol)
   {
     const CHROME_URL = "chrome://browser/content/styleeditor.xul";
     const CHROME_WINDOW_TYPE = "Tools:StyleEditor";
     const CHROME_WINDOW_FLAGS = "chrome,centerscreen,resizable,dialog=no";
 
     // focus currently open Style Editor window for this document, if any
     let contentWindow = gBrowser.selectedBrowser.contentWindow;
     let contentWindowID = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
       getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
     let enumerator = Services.wm.getEnumerator(CHROME_WINDOW_TYPE);
     while (enumerator.hasMoreElements()) {
       var win = enumerator.getNext();
       if (win.styleEditorChrome.contentWindowID == contentWindowID) {
+        if (aSelectedStyleSheet) {
+          win.styleEditorChrome.selectStyleSheet(aSelectedStyleSheet, aLine, aCol);
+        }
         win.focus();
         return win;
       }
     }
 
+    let args = {
+      contentWindow: contentWindow,
+      selectedStyleSheet: aSelectedStyleSheet,
+      line: aLine,
+      col: aCol
+    };
+    args.wrappedJSObject = args;
     let chromeWindow = Services.ww.openWindow(null, CHROME_URL, "_blank",
-                                              CHROME_WINDOW_FLAGS,
-                                              contentWindow);
+                                              CHROME_WINDOW_FLAGS, args);
     chromeWindow.focus();
     return chromeWindow;
   }
 };
 
 function onWebDeveloperMenuShowing() {
   document.getElementById("Tools:WebConsole").setAttribute("checked", HUDConsoleUI.getOpenHUD() != null);
 }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -85,16 +85,17 @@
         titlemodifier="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
         titlemodifier_normal="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
         titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
 #endif
         titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
         lightweightthemes="true"
         lightweightthemesfooter="browser-bottombox"
         windowtype="navigator:browser"
+        macanimationtype="document"
         screenX="4" screenY="4"
         browsingmode="normal"
         persist="screenX screenY width height sizemode">
 
 # All JS files which are not content (only) dependent that browser.xul
 # wishes to include *must* go into the global-scripts.inc file
 # so that they can be shared by macBrowserOverlay.xul.
 #include global-scripts.inc
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1261,16 +1261,22 @@
               }, 0, this.tabContainer);
             } else {
               setTimeout(function (tabContainer) {
                 if (t.pinned)
                   tabContainer._handleNewTab(t);
                 else {
                   t._animStartTime = Date.now();
                   t.setAttribute("fadein", "true");
+
+                  // This call to adjustTabstrip is redundant but needed so that
+                  // when opening a second tab, the first tab's close buttons
+                  // appears immediately rather than when the transition ends.
+                  if (tabContainer.childNodes.length == 2)
+                    tabContainer.adjustTabstrip();
                 }
               }, 0, this.tabContainer);
             }
 
             this.tabContainer.appendChild(t);
 
             // invalidate cache, because tabContainer is about to change
             this._browsers = null;
@@ -1360,17 +1366,18 @@
             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();
 
               // pretend the user typed this so it'll be available till
               // the document successfully loads
-              b.userTypedValue = aURI;
+              if (!isBlankPageURL(aURI))
+                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)
                 flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8;
@@ -1552,25 +1559,36 @@
 
       <method name="_beginRemoveTab">
         <parameter name="aTab"/>
         <parameter name="aTabWillBeMoved"/>
         <parameter name="aCloseWindowWithLastTab"/>
         <parameter name="aCloseWindowFastpath"/>
         <body>
           <![CDATA[
-            if (aTab.closing || this._windowIsClosing)
+            if (aTab.closing ||
+                aTab._pendingPermitUnload ||
+                this._windowIsClosing)
               return false;
 
             var browser = this.getBrowserForTab(aTab);
 
             if (!aTabWillBeMoved) {
               let ds = browser.docShell;
-              if (ds && ds.contentViewer && !ds.contentViewer.permitUnload())
-                return false;
+              if (ds && ds.contentViewer) {
+                // We need to block while calling permitUnload() because it
+                // processes the event queue and may lead to another removeTab()
+                // call before permitUnload() even returned.
+                aTab._pendingPermitUnload = true;
+                let permitUnload = ds.contentViewer.permitUnload();
+                delete aTab._pendingPermitUnload;
+
+                if (!permitUnload)
+                  return false;
+              }
             }
 
             var closeWindow = false;
             var newTab = false;
             if (this.tabs.length - this._removingTabs.length == 1) {
               closeWindow = aCloseWindowWithLastTab != null ? aCloseWindowWithLastTab :
                             !window.toolbar.visible ||
                               this.tabContainer._closeWindowWithLastTab;
@@ -3528,22 +3546,24 @@
 
           this.tabbrowser.swapBrowsersAndCloseOther(newTab, draggedTab);
 
           // We need to select the tab after we've done
           // swapBrowsersAndCloseOther, so that the updateCurrentBrowser
           // it triggers will correctly update our URL bar.
           this.tabbrowser.selectedTab = newTab;
         } else {
-          let url = browserDragAndDrop.drop(event, { });
+          // Pass true to disallow dropping javascript: or data: urls
+          let url;
+          try {
+            url = browserDragAndDrop.drop(event, { }, true);
+          } catch (ex) {}
 
           // valid urls don't contain spaces ' '; if we have a space it isn't a valid url.
-          // Also disallow dropping javascript: or data: urls--bail out
-          if (!url || !url.length || url.indexOf(" ", 0) != -1 ||
-              /^\s*(javascript|data):/.test(url))
+          if (!url || url.indexOf(" ") != -1)
             return;
 
           let bgLoad = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
 
           if (event.shiftKey)
             bgLoad = !bgLoad;
 
           let tab = this._getDragTargetTab(event);
@@ -4050,17 +4070,17 @@
         ]]></body>
       </method>
 
       <method name="_calcMouseTargetRect">
         <body><![CDATA[
           let alignRight = false;
 
           if (getComputedStyle(document.documentElement).direction == "rtl")
-            alighRight = !alignRight;
+            alignRight = !alignRight;
 
           let rect = this.getBoundingClientRect();
           this._mouseTargetRect = {
             top:    rect.top,
             bottom: rect.bottom,
             left:   alignRight ? window.innerWidth - rect.width : 0,
             right:  alignRight ? window.innerWidth : rect.width
           };
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -263,16 +263,17 @@ endif
                  test_bug628179.html \
                  browser_wyciwyg_urlbarCopying.js \
                  test_wyciwyg_copying.html \
                  authenticate.sjs \
                  browser_minimize.js \
                  browser_aboutSyncProgress.js \
                  browser_middleMouse_inherit.js \
                  redirect_bug623155.sjs \
+                 browser_tabDrop.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_tabDrop.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  let newTab = gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
+  registerCleanupFunction(function () {
+    gBrowser.removeTab(newTab);
+  });
+
+  let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
+                     getService(Ci.mozIJSSubScriptLoader);
+  let chromeUtils = {};
+  scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", chromeUtils);
+
+  let tabContainer = gBrowser.tabContainer;
+  var receivedDropCount = 0;
+  function dropListener() {
+    receivedDropCount++;
+    if (receivedDropCount == triggeredDropCount) {
+      is(openedTabs, validDropCount, "correct number of tabs were opened");
+      executeSoon(finish);
+    }
+  }
+  tabContainer.addEventListener("drop", dropListener, false);
+  registerCleanupFunction(function () {
+    tabContainer.removeEventListener("drop", dropListener, false);
+  });
+
+  var openedTabs = 0;
+  function tabOpenListener(e) {
+    openedTabs++;
+    let tab = e.target;
+    executeSoon(function () {
+      gBrowser.removeTab(tab);
+    });
+  }
+
+  tabContainer.addEventListener("TabOpen", tabOpenListener, false);
+  registerCleanupFunction(function () {
+    tabContainer.removeEventListener("TabOpen", tabOpenListener, false);
+  });
+
+  var triggeredDropCount = 0;
+  var validDropCount = 0;
+  function drop(text, valid) {
+    triggeredDropCount++;
+    if (valid)
+      validDropCount++;
+    executeSoon(function () {
+      // A drop type of "link" onto an existing tab would normally trigger a
+      // load in that same tab, but tabbrowser code in _getDragTargetTab treats
+      // drops on the outer edges of a tab differently (loading a new tab
+      // instead). The events created by synthesizeDrop have all of their
+      // coordinates set to 0 (screenX/screenY), so they're treated as drops
+      // on the outer edge of the tab, thus they open new tabs.
+      chromeUtils.synthesizeDrop(newTab, newTab, [[{type: "text/plain", data: text}]], "link", window, EventUtils);
+    });
+  }
+
+  // Begin and end with valid drops to make sure we wait for all drops before
+  // ending the test
+  drop("mochi.test/first", true);
+  drop("javascript:'bad'");
+  drop("jAvascript:'bad'");
+  drop("space bad");
+  drop("mochi.test/second", true);
+  drop("data:text/html,bad");
+  drop("mochi.test/third", true);
+}
--- a/browser/branding/official/configure.sh
+++ b/browser/branding/official/configure.sh
@@ -1,2 +1,1 @@
 MOZ_APP_DISPLAYNAME=Firefox
-MOZ_UA_BUILDID=20100101
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -67,16 +67,17 @@
 /* :::::::: Constants and Helpers ::::::::::::::: */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/TelemetryStopwatch.jsm");
 
 const STATE_RUNNING_STR = "running";
 const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 megabytes
 
 function debug(aMsg) {
   aMsg = ("SessionStartup: " + aMsg).replace(/\S{80}/g, "$&\n");
   Services.console.logStringMessage(aMsg);
 }
@@ -122,45 +123,51 @@ SessionStartup.prototype = {
       return;
 
     // get string containing session state
     let iniString = this._readStateFile(sessionFile);
     if (!iniString)
       return;
 
     // parse the session state into a JS object
+    // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
+    if (iniString.charAt(0) == '(')
+      iniString = iniString.slice(1, -1);
+    let corruptFile = false;
     try {
-      // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
-      if (iniString.charAt(0) == '(')
-        iniString = iniString.slice(1, -1);
+      this._initialState = JSON.parse(iniString);
+    }
+    catch (ex) {
+      debug("The session file contained un-parse-able JSON: " + ex);
+      // Try to eval.
+      // evalInSandbox will throw if iniString is not parse-able.
       try {
-        this._initialState = JSON.parse(iniString);
-      }
-      catch (exJSON) {
         var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
         this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
+      } catch(ex) {
+        debug("The session file contained un-eval-able JSON: " + ex);
+        corruptFile = true;
       }
+    }
+    Services.telemetry.getHistogramById("FX_SESSION_RESTORE_CORRUPT_FILE").add(corruptFile);
 
-      // If this is a normal restore then throw away any previous session
-      if (!doResumeSessionOnce)
-        delete this._initialState.lastSessionState;
-    }
-    catch (ex) { debug("The session file is invalid: " + ex); }
+    // If this is a normal restore then throw away any previous session
+    if (!doResumeSessionOnce)
+      delete this._initialState.lastSessionState;
 
     let resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash");
     let lastSessionCrashed =
       this._initialState && this._initialState.session &&
       this._initialState.session.state &&
       this._initialState.session.state == STATE_RUNNING_STR;
 
     // Report shutdown success via telemetry. Shortcoming here are
     // being-killed-by-OS-shutdown-logic, shutdown freezing after
     // session restore was written, etc.
-    let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
-    Telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
+    Services.telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
 
     // set the startup type
     if (lastSessionCrashed && resumeFromCrash)
       this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
     else if (!lastSessionCrashed && doResumeSession)
       this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
     else if (this._initialState)
       this._sessionType = Ci.nsISessionStartup.DEFER_SESSION;
@@ -291,19 +298,21 @@ SessionStartup.prototype = {
   /**
    * Reads a session state file into a string and lets
    * observers modify the state before it's being used
    *
    * @param aFile is any nsIFile
    * @returns a session state string
    */
   _readStateFile: function sss_readStateFile(aFile) {
+    TelemetryStopwatch.start("FX_SESSION_RESTORE_READ_FILE_MS");
     var stateString = Cc["@mozilla.org/supports-string;1"].
                         createInstance(Ci.nsISupportsString);
     stateString.data = this._readFile(aFile) || "";
+    TelemetryStopwatch.finish("FX_SESSION_RESTORE_READ_FILE_MS");
 
     Services.obs.notifyObservers(stateString, "sessionstore-state-read", "");
 
     return stateString.data;
   },
 
   /**
    * reads a file into a string
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -126,16 +126,17 @@ const TAB_EVENTS = ["TabOpen", "TabClose
 #endif
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 // debug.js adds NS_ASSERT. cf. bug 669196
 Cu.import("resource://gre/modules/debug.js");
 
 Cu.import("resource:///modules/TelemetryTimestamps.jsm");
+Cu.import("resource:///modules/TelemetryStopwatch.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
   Cu.import("resource://gre/modules/NetUtil.jsm");
   return NetUtil;
 });
 
 XPCOMUtils.defineLazyGetter(this, "ScratchpadManager", function() {
   Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
@@ -3648,16 +3649,18 @@ SessionStoreService.prototype = {
     // if we're in private browsing mode, do nothing
     if (this._inPrivateBrowsing)
       return;
 
     // If crash recovery is disabled, we only want to resume with pinned tabs
     // if we crash.
     let pinnedOnly = this._loadState == STATE_RUNNING && !this._resume_from_crash;
 
+    TelemetryStopwatch.start("FX_SESSION_RESTORE_COLLECT_DATA_MS");
+
     var oState = this._getCurrentState(aUpdateAll, pinnedOnly);
     if (!oState)
       return;
 
 #ifndef XP_MACOSX
     // We want to restore closed windows that are marked with _shouldRestore.
     // We're doing this here because we want to control this only when saving
     // the file.
@@ -3686,26 +3689,30 @@ SessionStoreService.prototype = {
         Services.prefs.savePrefFile(null);
       }
     }
 
     // Persist the last session if we deferred restoring it
     if (this._lastSessionState)
       oState.lastSessionState = this._lastSessionState;
 
+    TelemetryStopwatch.finish("FX_SESSION_RESTORE_COLLECT_DATA_MS");
+
     this._saveStateObject(oState);
   },
 
   /**
    * write a state object to disk
    */
   _saveStateObject: function sss_saveStateObject(aStateObj) {
+    TelemetryStopwatch.start("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
     var stateString = Cc["@mozilla.org/supports-string;1"].
                         createInstance(Ci.nsISupportsString);
     stateString.data = this._toJSONString(aStateObj);
+    TelemetryStopwatch.finish("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
 
     Services.obs.notifyObservers(stateString, "sessionstore-state-write", "");
 
     // don't touch the file if an observer has deleted all state data
     if (stateString.data)
       this._writeFile(this._sessionFile, stateString.data);
 
     this._lastSaveTime = Date.now();
@@ -3804,17 +3811,17 @@ SessionStoreService.prototype = {
    *        Object containing session data
    */
   _openWindowWithState: function sss_openWindowWithState(aState) {
     var argString = Cc["@mozilla.org/supports-string;1"].
                     createInstance(Ci.nsISupportsString);
     argString.data = "";
 
     // Build feature string
-    let features = "chrome,dialog=no,all";
+    let features = "chrome,dialog=no,macsuppressanimation,all";
     let winState = aState.windows[0];
     WINDOW_ATTRIBUTES.forEach(function(aFeature) {
       // Use !isNaN as an easy way to ignore sizemode and check for numbers
       if (aFeature in winState && !isNaN(winState[aFeature]))
         features += "," + aFeature + "=" + winState[aFeature];
     });
 
     var window =
@@ -4422,31 +4429,33 @@ SessionStoreService.prototype = {
   /**
    * write file to disk
    * @param aFile
    *        nsIFile
    * @param aData
    *        String data
    */
   _writeFile: function sss_writeFile(aFile, aData) {
+    TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS");
     // Initialize the file output stream.
     var ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
                   createInstance(Ci.nsIFileOutputStream);
     ostream.init(aFile, 0x02 | 0x08 | 0x20, 0600, ostream.DEFER_OPEN);
 
     // Obtain a converter to convert our data to a UTF-8 encoded input stream.
     var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
                     createInstance(Ci.nsIScriptableUnicodeConverter);
     converter.charset = "UTF-8";
 
     // Asynchronously copy the data to the file.
     var istream = converter.convertToInputStream(aData);
     var self = this;
     NetUtil.asyncCopy(istream, ostream, function(rc) {
       if (Components.isSuccessCode(rc)) {
+        TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_MS");
         Services.obs.notifyObservers(null,
                                      "sessionstore-state-write-complete",
                                      "");
       }
     });
   }
 };
 
copy from browser/config/mozconfigs/macosx-universal/nightly
copy to browser/config/mozconfigs/macosx-lion-universal/nightly
--- a/browser/config/mozconfigs/macosx-universal/nightly
+++ b/browser/config/mozconfigs/macosx-lion-universal/nightly
@@ -10,14 +10,15 @@ ac_add_options --disable-install-strip
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
-mk_add_options MOZ_MAKE_FLAGS="-j4"
+mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+ac_add_options --with-ccache
copy from browser/config/mozconfigs/macosx-universal/release
copy to browser/config/mozconfigs/macosx-lion-universal/release
--- a/browser/config/mozconfigs/macosx-universal/release
+++ b/browser/config/mozconfigs/macosx-lion-universal/release
@@ -12,8 +12,9 @@ export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
+ac_add_options --with-ccache
copy from browser/config/mozconfigs/macosx-universal/shark
copy to browser/config/mozconfigs/macosx-lion-universal/shark
--- a/browser/config/mozconfigs/macosx-universal/shark
+++ b/browser/config/mozconfigs/macosx-lion-universal/shark
@@ -7,19 +7,20 @@ ac_add_options --enable-application=brow
 
 ac_add_options --disable-tests
 ac_add_options --disable-install-strip
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Enable parallel compiling
-mk_add_options MOZ_MAKE_FLAGS="-j4"
+mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # shark specific options
 ac_add_options --enable-shark
 ac_add_options --enable-dtrace
 
 # Need this to prevent name conflicts with the normal nightly build packages
 export MOZ_PKG_SPECIAL="shark"
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+ac_add_options --with-ccache
copy from browser/config/mozconfigs/macosx32/debug
copy to browser/config/mozconfigs/macosx32-lion/debug
--- a/browser/config/mozconfigs/macosx32/debug
+++ b/browser/config/mozconfigs/macosx32-lion/debug
@@ -1,11 +1,12 @@
 . $topsrcdir/build/macosx/mozconfig.leopard
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 
 # Enable parallel compiling
-mk_add_options MOZ_MAKE_FLAGS="-j4"
+mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
+ac_add_options --with-ccache
copy from browser/config/mozconfigs/macosx64/debug
copy to browser/config/mozconfigs/macosx64-lion/debug
--- a/browser/config/mozconfigs/macosx64/debug
+++ b/browser/config/mozconfigs/macosx64-lion/debug
@@ -1,16 +1,17 @@
 . $topsrcdir/build/macosx/common
 
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-accessibility
 
 # Enable parallel compiling
-mk_add_options MOZ_MAKE_FLAGS="-j4"
+mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+ac_add_options --with-ccache
copy from browser/config/mozconfigs/macosx64/l10n-mozconfig
copy to browser/config/mozconfigs/macosx64-lion/l10n-mozconfig
--- a/browser/config/mozconfigs/macosx64/l10n-mozconfig
+++ b/browser/config/mozconfigs/macosx64-lion/l10n-mozconfig
@@ -1,4 +1,5 @@
 ac_add_options --with-l10n-base=../../l10n-central
 ac_add_options --enable-official-branding
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
+ac_add_options --with-ccache
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -67,16 +67,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_location-changes.js \
 	browser_dbg_script-switching.js \
 	browser_dbg_pause-resume.js \
 	browser_dbg_update-editor-mode.js \
 	browser_dbg_select-line.js \
+	browser_dbg_clean-exit.js \
 	head.js \
 	$(NULL)
 
 _BROWSER_TEST_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_clean-exit.js
@@ -0,0 +1,42 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that closing a tab with the debugger in a paused state exits cleanly.
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+
+const DEBUGGER_TAB_URL = "http://example.com/browser/browser/devtools/" +
+                         "debugger/test/" +
+                         "browser_dbg_debuggerstatement.html";
+
+function test() {
+  debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.debuggerWindow;
+
+    testCleanExit();
+  });
+}
+
+function testCleanExit() {
+  gPane.activeThread.addOneTimeListener("framesadded", function() {
+    Services.tm.currentThread.dispatch({ run: function() {
+      is(gDebugger.StackFrames.activeThread.paused, true,
+        "Should be paused after the debugger statement.");
+
+      gPane._client.addOneTimeListener("tabDetached", function () {
+        finish();
+      });
+      removeTab(gTab);
+    }}, 0);
+  });
+
+  gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
+}
--- a/browser/devtools/highlighter/inspector.jsm
+++ b/browser/devtools/highlighter/inspector.jsm
@@ -758,16 +758,19 @@ InspectorUI.prototype = {
         this.store.setValue(winID, "ruleView", ruleViewStore);
       }
 
       this.ruleView = new CssRuleView(doc, ruleViewStore);
 
       this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
       this.ruleView.element.addEventListener("CssRuleViewChanged",
                                              this.boundRuleViewChanged);
+      this.cssRuleViewBoundCSSLinkClicked = this.ruleViewCSSLinkClicked.bind(this);
+      this.ruleView.element.addEventListener("CssRuleViewCSSLinkClicked",
+                                             this.cssRuleViewBoundCSSLinkClicked);
 
       doc.documentElement.appendChild(this.ruleView.element);
       this.ruleView.highlight(this.selection);
       Services.obs.notifyObservers(null,
         INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, null);
     }.bind(this);
 
     iframe.addEventListener("load", boundLoadListener, true);
@@ -796,26 +799,52 @@ InspectorUI.prototype = {
 
   ruleViewChanged: function IUI_ruleViewChanged()
   {
     this.isDirty = true;
     this.nodeChanged(this.ruleViewObject);
   },
 
   /**
+   * When a css link is clicked this method is called in order to either:
+   *   1. Open the link in view source (for element style attributes)
+   *   2. Open the link in the style editor
+   *
+   * @param aEvent The event containing the style rule to act on
+   */
+  ruleViewCSSLinkClicked: function(aEvent)
+  {
+    if (!this.chromeWin) {
+      return;
+    }
+
+    let rule = aEvent.detail.rule;
+    let styleSheet = rule.sheet;
+
+    if (styleSheet) {
+      this.chromeWin.StyleEditor.openChrome(styleSheet, rule.ruleLine);
+    } else {
+      let href = rule.elementStyle.element.ownerDocument.location.href;
+      this.chromeWin.openUILinkIn("view-source:" + href, "window");
+    }
+  },
+
+  /**
    * Destroy the rule view.
    */
   destroyRuleView: function IUI_destroyRuleView()
   {
     let iframe = this.getToolIframe(this.ruleViewObject);
     iframe.parentNode.removeChild(iframe);
 
     if (this.ruleView) {
       this.ruleView.element.removeEventListener("CssRuleViewChanged",
                                                 this.boundRuleViewChanged);
+      this.ruleView.element.removeEventListener("CssRuleViewCSSLinkClicked",
+                                                this.cssRuleViewBoundCSSLinkClicked);
       delete boundRuleViewChanged;
       this.ruleView.clear();
       delete this.ruleView;
     }
   },
 
   /////////////////////////////////////////////////////////////////////////
   //// Utility Methods
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -46,16 +46,17 @@
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
 
 <window id="main-window"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="&window.title;"
         windowtype="devtools:scratchpad"
+        macanimationtype="document"
         screenX="4" screenY="4"
         width="640" height="480"
         persist="screenX screenY width height sizemode">
 
 <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
 <script type="application/javascript" src="chrome://browser/content/scratchpad.js"/>
 
 <commandset id="editMenuCommands"/>
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -73,16 +73,19 @@ const ORION_THEMES = {
  * to Orion events.
  */
 const ORION_EVENTS = {
   ContextMenu: "ContextMenu",
   TextChanged: "ModelChanged",
   Selection: "Selection",
   Focus: "Focus",
   Blur: "Blur",
+  MouseOver: "MouseOver",
+  MouseOut: "MouseOut",
+  MouseMove: "MouseMove",
 };
 
 /**
  * Known Orion annotation types.
  */
 const ORION_ANNOTATION_TYPES = {
   currentBracket: "orion.annotation.currentBracket",
   matchingBracket: "orion.annotation.matchingBracket",
--- a/browser/devtools/sourceeditor/source-editor.jsm
+++ b/browser/devtools/sourceeditor/source-editor.jsm
@@ -156,16 +156,40 @@ SourceEditor.EVENTS = {
    * The focus event is fired when the editor is focused.
    */
   FOCUS: "Focus",
 
   /**
    * The blur event is fired when the editor goes out of focus.
    */
   BLUR: "Blur",
+
+  /**
+   * The MouseMove event is sent when the user moves the mouse over a line
+   * annotation. The event object properties:
+   *   - event - the DOM mousemove event object.
+   *   - x and y - the mouse coordinates relative to the document being edited.
+   */
+  MOUSE_MOVE: "MouseMove",
+
+  /**
+   * The MouseOver event is sent when the mouse pointer enters a line
+   * annotation. The event object properties:
+   *   - event - the DOM mouseover event object.
+   *   - x and y - the mouse coordinates relative to the document being edited.
+   */
+  MOUSE_OVER: "MouseOver",
+
+  /**
+   * This MouseOut event is sent when the mouse pointer exits a line
+   * annotation. The event object properties:
+   *   - event - the DOM mouseout event object.
+   *   - x and y - the mouse coordinates relative to the document being edited.
+   */
+  MOUSE_OUT: "MouseOut",
 };
 
 /**
  * Extend a destination object with properties from a source object.
  *
  * @param object aDestination
  * @param object aSource
  */
--- a/browser/devtools/sourceeditor/test/Makefile.in
+++ b/browser/devtools/sourceeditor/test/Makefile.in
@@ -50,12 +50,13 @@ include $(topsrcdir)/config/rules.mk
 		browser_bug687573_vscroll.js \
 		browser_bug687568_pagescroll.js \
 		browser_bug687580_drag_and_drop.js \
 		browser_bug684546_reset_undo.js \
 		browser_bug695035_middle_click_paste.js \
 		browser_bug687160_line_api.js \
 		browser_bug650345_find.js \
 		browser_bug703692_focus_blur.js \
+		browser_bug725388_mouse_events.js \
 		head.js \
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/sourceeditor/test/browser_bug725388_mouse_events.js
@@ -0,0 +1,97 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let tempScope = {};
+Cu.import("resource:///modules/source-editor.jsm", tempScope);
+let SourceEditor = tempScope.SourceEditor;
+
+let testWin;
+let editor;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
+    "<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
+    " title='Test for bug 725388' width='600' height='500'><hbox flex='1'/></window>";
+  const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
+
+  testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
+  testWin.addEventListener("load", function onWindowLoad() {
+    testWin.removeEventListener("load", onWindowLoad, false);
+    waitForFocus(initEditor, testWin);
+  }, false);
+}
+
+function initEditor()
+{
+  let hbox = testWin.document.querySelector("hbox");
+
+  editor = new SourceEditor();
+  editor.init(hbox, {}, editorLoaded);
+}
+
+function editorLoaded()
+{
+  let text = "BrowserBug - 725388";
+  editor.setText(text);
+
+  let target = editor.editorElement;
+  let targetWin = target.ownerDocument.defaultView;
+
+  let mMoveHandler = function(aEvent) {
+    editor.removeEventListener(SourceEditor.EVENTS.MOUSE_MOVE, mMoveHandler);
+
+    is(aEvent.event.type, "mousemove", "MouseMove event fired.");
+
+    editor.addEventListener(SourceEditor.EVENTS.MOUSE_OVER, mOverHandler);
+    waitForFocus(function() {
+      EventUtils.synthesizeMouse(target, 10, 10, {type: "mouseover"},
+                                 targetWin);
+    });
+  };
+
+  let mOverHandler = function(aEvent) {
+    editor.removeEventListener(SourceEditor.EVENTS.MOUSE_OVER, mOverHandler);
+
+    is(aEvent.event.type, "mouseover", "MouseOver event fired.");
+
+    editor.addEventListener(SourceEditor.EVENTS.MOUSE_OUT, mOutHandler);
+    waitForFocus(function() {
+      EventUtils.synthesizeMouse(target, -10, -10, {type: "mouseout"},
+                                 targetWin);
+    }, targetWin);
+  };
+
+  let mOutHandler = function(aEvent) {
+    editor.removeEventListener(SourceEditor.EVENTS.MOUSE_OUT, mOutHandler);
+
+    is(aEvent.event.type, "mouseout", "MouseOut event fired.");
+    executeSoon(testEnd);
+  };
+
+  editor.addEventListener(SourceEditor.EVENTS.MOUSE_MOVE, mMoveHandler);
+
+  editor.focus();
+  waitForFocus(function() {
+  EventUtils.synthesizeMouse(target, 1, 1, {type: "mousemove"},
+                             targetWin);
+  }, targetWin);
+}
+
+function testEnd()
+{
+  if (editor) {
+    editor.destroy();
+  }
+  if (testWin) {
+    testWin.close();
+  }
+  testWin = editor = null;
+
+  waitForFocus(finish, window);
+}
--- a/browser/devtools/styleeditor/StyleEditor.jsm
+++ b/browser/devtools/styleeditor/StyleEditor.jsm
@@ -141,17 +141,17 @@ StyleEditor.prototype = {
 
   /**
    * Retrieve the stylesheet this editor is attached to.
    *
    * @return DOMStyleSheet
    */
   get styleSheet()
   {
-    assert(this._styleSheet, "StyleSheet must be loaded first.")
+    assert(this._styleSheet, "StyleSheet must be loaded first.");
     return this._styleSheet;
   },
 
   /**
    * Retrieve the index (order) of stylesheet in the document.
    *
    * @return number
    */
@@ -916,19 +916,21 @@ StyleEditor.prototype = {
   {
     // insert the origin editor instance as first argument
     if (!aArgs) {
       aArgs = [this];
     } else {
       aArgs.unshift(this);
     }
 
+    // copy the list of listeners to allow adding/removing listeners in handlers
+    let listeners = this._actionListeners.concat();
     // trigger all listeners that have this action handler
-    for (let i = 0; i < this._actionListeners.length; ++i) {
-      let listener = this._actionListeners[i];
+    for (let i = 0; i < listeners.length; ++i) {
+      let listener = listeners[i];
       let actionHandler = listener["on" + aName];
       if (actionHandler) {
         actionHandler.apply(listener, aArgs);
       }
     }
 
     // when a flag got changed, user-facing state need to be persisted
     if (aName == "FlagChange") {
--- a/browser/devtools/styleeditor/StyleEditorChrome.jsm
+++ b/browser/devtools/styleeditor/StyleEditorChrome.jsm
@@ -265,19 +265,21 @@ StyleEditorChrome.prototype = {
   {
     // insert the origin Chrome instance as first argument
     if (!aArgs) {
       aArgs = [this];
     } else {
       aArgs.unshift(this);
     }
 
-    // trigger all listeners that have this named handler
-    for (let i = 0; i < this._listeners.length; ++i) {
-      let listener = this._listeners[i];
+    // copy the list of listeners to allow adding/removing listeners in handlers
+    let listeners = this._listeners.concat();
+    // trigger all listeners that have this named handler.
+    for (let i = 0; i < listeners.length; i++) {
+      let listener = listeners[i];
       let handler = listener["on" + aName];
       if (handler) {
         handler.apply(listener, aArgs);
       }
     }
   },
 
   /**
@@ -324,20 +326,20 @@ StyleEditorChrome.prototype = {
    * Populate the chrome UI according to the content document.
    *
    * @see StyleEditor._setupShadowStyleSheet
    */
   _populateChrome: function SEC__populateChrome()
   {
     this._resetChrome();
 
+    let document = this.contentDocument;
     this._document.title = _("chromeWindowTitle",
-          this.contentDocument.title || this.contentDocument.location.href);
+      document.title || document.location.href);
 
-    let document = this.contentDocument;
     for (let i = 0; i < document.styleSheets.length; ++i) {
       let styleSheet = document.styleSheets[i];
 
       let editor = new StyleEditor(document, styleSheet);
       editor.addActionListener(this);
       this._editors.push(editor);
     }
 
@@ -348,16 +350,89 @@ StyleEditorChrome.prototype = {
     // NOT loaded/ready yet. This also helps responsivity during loading when
     // there are many heavy stylesheets.
     this._editors.forEach(function (aEditor) {
       this._window.setTimeout(aEditor.load.bind(aEditor), 0);
     }, this);
   },
 
   /**
+   * selects a stylesheet and optionally moves the cursor to a selected line
+   *
+   * @param {CSSStyleSheet} [aSheet]
+   *        Stylesheet that should be selected. If a stylesheet is not passed
+   *        and the editor is not initialized we focus the first stylesheet. If
+   *        a stylesheet is not passed and the editor is initialized we ignore
+   *        the call.
+   * @param {Number} [aLine]
+   *        Line to which the caret should be moved (one-indexed).
+   * @param {Number} [aCol]
+   *        Column to which the caret should be moved (one-indexed).
+   */
+  selectStyleSheet: function SEC_selectSheet(aSheet, aLine, aCol)
+  {
+    let select = function DEC_select(aEditor) {
+      let summary = aSheet ? this.getSummaryElementForEditor(aEditor)
+                           : this._view.getSummaryElementByOrdinal(0);
+      let setCaret = false;
+
+      if (aLine || aCol) {
+        aLine = aLine || 1;
+        aCol = aCol || 1;
+        setCaret = true;
+      }
+      if (!aEditor.sourceEditor) {
+        // If a line or column was specified we move the caret appropriately.
+        if (setCaret) {
+          aEditor.addActionListener({
+            onAttach: function SEC_selectSheet_onAttach()
+            {
+              aEditor.removeActionListener(this);
+              aEditor.sourceEditor.setCaretPosition(aLine - 1, aCol - 1);
+            }
+          });
+        }
+        this._view.activeSummary = summary;
+      } else {
+        this._view.activeSummary = summary;
+
+        // If a line or column was specified we move the caret appropriately.
+        if (setCaret) {
+          aEditor.sourceEditor.setCaretPosition(aLine - 1, aCol - 1);
+        }
+      }
+    }.bind(this);
+
+    if (!this.editors.length) {
+      // We are in the main initialization phase so we wait for the editor
+      // containing the target stylesheet to be added and select the target
+      // stylesheet, optionally moving the cursor to a selected line.
+      this.addChromeListener({
+        onEditorAdded: function SEC_selectSheet_onEditorAdded(aChrome, aEditor) {
+          if ((!aSheet && aEditor.styleSheetIndex == 0) ||
+              aEditor.styleSheet == aSheet) {
+            aChrome.removeChromeListener(this);
+            select(aEditor);
+          }
+        }
+      });
+    } else if (aSheet) {
+      // We are already initialized and a stylesheet has been specified. Here
+      // we iterate through the editors and select the one containing the target
+      // stylesheet, optionally moving the cursor to a selected line.
+      for each (let editor in this.editors) {
+        if (editor.styleSheet == aSheet) {
+          select(editor);
+          break;
+        }
+      }
+    }
+  },
+
+  /**
    * Disable all UI, effectively making editors read-only.
    * This is automatically called when no content window is attached.
    *
    * @see contentWindow
    */
   _disableChrome: function SEC__disableChrome()
   {
     let matches = this._root.querySelectorAll("button,toolbarbutton,textbox");
@@ -450,19 +525,18 @@ StyleEditorChrome.prototype = {
 
         aSummary.addEventListener("focus", function onSummaryFocus(aEvent) {
           if (aEvent.target == aSummary) {
             // autofocus the stylesheet name
             aSummary.querySelector(".stylesheet-name").focus();
           }
         }, false);
 
-        // autofocus the first or new stylesheet
-        if (editor.styleSheetIndex == 0 ||
-            editor.hasFlag(StyleEditorFlags.NEW)) {
+        // autofocus new stylesheets
+        if (editor.hasFlag(StyleEditorFlags.NEW)) {
           this._view.activeSummary = aSummary;
         }
 
         this._triggerChromeListeners("EditorAdded", [editor]);
       }.bind(this),
       onHide: function ASV_onItemShow(aSummary, aDetails, aData) {
         aData.editor.onHide();
       },
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -127,13 +127,15 @@
                data-placeholder="&editorTextbox.placeholder;"/>
     </xul:box>
   </div> <!-- #splitview-templates -->
 </xul:box>   <!-- .splitview-root -->
 
 <xul:script type="application/javascript"><![CDATA[
 Components.utils.import("resource:///modules/devtools/StyleEditorChrome.jsm");
 let chromeRoot = document.getElementById("style-editor-chrome");
-let contentWindow = window.arguments[0];
+let args = window.arguments[0].wrappedJSObject;
+let contentWindow = args.contentWindow;
 let chrome = new StyleEditorChrome(chromeRoot, contentWindow);
+chrome.selectStyleSheet(args.selectedStyleSheet, args.line, args.col);
 window.styleEditorChrome = chrome;
 ]]></xul:script>
 </xul:window>
--- a/browser/devtools/styleeditor/test/Makefile.in
+++ b/browser/devtools/styleeditor/test/Makefile.in
@@ -46,16 +46,17 @@ include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
                  browser_styleeditor_enabled.js \
                  browser_styleeditor_filesave.js \
                  browser_styleeditor_import.js \
                  browser_styleeditor_init.js \
                  browser_styleeditor_loading.js \
                  browser_styleeditor_new.js \
+                 browser_styleeditor_passedinsheet.js \
                  browser_styleeditor_pretty.js \
                  browser_styleeditor_readonly.js \
                  browser_styleeditor_reopen.js \
                  browser_styleeditor_sv_keynav.js \
                  browser_styleeditor_sv_resize.js \
                  four.html \
                  head.js \
                  media.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_passedinsheet.js
@@ -0,0 +1,61 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TESTCASE_URI = TEST_BASE + "simple.html";
+const LINE = 6;
+const COL = 2;
+
+let editor = null;
+let sheet = null;
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedBrowser.addEventListener("load", function () {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+    run();
+  }, true);
+  content.location = TESTCASE_URI;
+}
+
+function run()
+{
+  sheet = content.document.styleSheets[1];
+  launchStyleEditorChrome(function attachListeners(aChrome) {
+    aChrome.addChromeListener({
+      onEditorAdded: checkSourceEditor
+    });
+  }, sheet, LINE, COL);
+}
+
+function checkSourceEditor(aChrome, aEditor)
+{
+  if (!aEditor.sourceEditor) {
+    aEditor.addActionListener({
+      onAttach: function (aEditor) {
+        aEditor.removeActionListener(this);
+        validate(aEditor);
+      }
+    });
+  } else {
+    validate(aEditor);
+  }
+}
+
+function validate(aEditor)
+{
+  info("validating style editor");
+  let sourceEditor = aEditor.sourceEditor;
+  let caretPosition = sourceEditor.getCaretPosition();
+  is(caretPosition.line, LINE - 1, "caret row is correct"); // index based
+  is(caretPosition.col, COL - 1, "caret column is correct");
+  is(aEditor.styleSheet, sheet, "loaded stylesheet matches document stylesheet");
+  finishUp();
+}
+
+function finishUp()
+{
+  editor = sheet = null;
+  finish();
+}
--- a/browser/devtools/styleeditor/test/head.js
+++ b/browser/devtools/styleeditor/test/head.js
@@ -14,33 +14,33 @@ function cleanup()
     gChromeWindow.close();
     gChromeWindow = null;
   }
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 }
 
-function launchStyleEditorChrome(aCallback)
+function launchStyleEditorChrome(aCallback, aSheet, aLine, aCol)
 {
-  gChromeWindow = StyleEditor.openChrome();
+  gChromeWindow = StyleEditor.openChrome(aSheet, aLine, aCol);
   if (gChromeWindow.document.readyState != "complete") {
     gChromeWindow.addEventListener("load", function onChromeLoad() {
       gChromeWindow.removeEventListener("load", onChromeLoad, true);
       gChromeWindow.styleEditorChrome._alwaysDisableAnimations = true;
       aCallback(gChromeWindow.styleEditorChrome);
     }, true);
   } else {
     gChromeWindow.styleEditorChrome._alwaysDisableAnimations = true;
     aCallback(gChromeWindow.styleEditorChrome);
   }
 }
 
-function addTabAndLaunchStyleEditorChromeWhenLoaded(aCallback)
+function addTabAndLaunchStyleEditorChromeWhenLoaded(aCallback, aSheet, aLine, aCol)
 {
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
     gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
-    launchStyleEditorChrome(aCallback);
+    launchStyleEditorChrome(aCallback, aSheet, aLine, aCol);
   }, true);
 }
 
 registerCleanupFunction(cleanup);
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -268,24 +268,28 @@ CssHtmlTree.prototype = {
    */
   highlight: function CssHtmlTree_highlight(aElement)
   {
     this.viewedElement = aElement;
     this._unmatchedProperties = null;
     this._matchedProperties = null;
 
     if (this.htmlComplete) {
+      this.refreshSourceFilter();
       this.refreshPanel();
     } else {
       if (this._refreshProcess) {
         this._refreshProcess.cancel();
       }
 
       CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
 
+      // Refresh source filter ... this must be done after templateRoot has been
+      // processed.
+      this.refreshSourceFilter();
       this.numVisibleProperties = 0;
       let fragment = this.doc.createDocumentFragment();
       this._refreshProcess = new UpdateProcess(this.win, CssHtmlTree.propertyNames, {
         onItem: function(aPropertyName) {
           // Per-item callback.
           if (this.viewedElement != aElement || !this.styleInspector.isOpen()) {
             return false;
           }
@@ -357,31 +361,38 @@ CssHtmlTree.prototype = {
 
     this._filterChangedTimeout = win.setTimeout(function() {
       this.refreshPanel();
       this._filterChangeTimeout = null;
     }.bind(this), FILTER_CHANGED_TIMEOUT);
   },
 
   /**
-   * The change event handler for the onlyUserStyles checkbox. When
-   * onlyUserStyles.checked is true we do not display properties that have no
-   * matched selectors, and we do not display UA styles. If .checked is false we
-   * do display even properties with no matched selectors, and we include the UA
-   * styles.
+   * The change event handler for the onlyUserStyles checkbox.
    *
    * @param {Event} aEvent the DOM Event object.
    */
   onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent)
   {
+    this.refreshSourceFilter();
+    this.refreshPanel();
+  },
+
+  /**
+   * When onlyUserStyles.checked is true we only display properties that have
+   * matched selectors and have been included by the document or one of the
+   * document's stylesheets. If .checked is false we display all properties
+   * including those that come from UA stylesheets.
+   */
+  refreshSourceFilter: function CssHtmlTree_setSourceFilter()
+  {
     this._matchedProperties = null;
     this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
                                  CssLogic.FILTER.ALL :
                                  CssLogic.FILTER.UA;
-    this.refreshPanel();
   },
 
   /**
    * The CSS as displayed by the UI.
    */
   createStyleViews: function CssHtmlTree_createStyleViews()
   {
     if (CssHtmlTree.propertyNames) {
@@ -969,9 +980,29 @@ SelectorView.prototype = {
           this.tree.styleInspector.selectFromPath(source);
           aEvent.preventDefault();
         }.bind(this), false);
       result += ".style";
     }
 
     return result;
   },
+
+  /**
+   * When a css link is clicked this method is called in order to either:
+   *   1. Open the link in view source (for element style attributes).
+   *   2. Open the link in the style editor.
+   *
+   * @param aEvent The click event
+   */
+  openStyleEditor: function(aEvent)
+  {
+    if (this.selectorInfo.selector._cssRule._cssSheet) {
+      let styleSheet = this.selectorInfo.selector._cssRule._cssSheet.domSheet;
+      let line = this.selectorInfo.ruleLine;
+
+      this.tree.win.StyleEditor.openChrome(styleSheet, line);
+    } else {
+      let href = this.selectorInfo.sourceElement.ownerDocument.location.href;
+      this.tree.win.openUILinkIn("view-source:" + href, "window");
+    }
+  },
 };
--- a/browser/devtools/styleinspector/CssLogic.jsm
+++ b/browser/devtools/styleinspector/CssLogic.jsm
@@ -227,17 +227,17 @@ CssLogic.prototype = {
     let oldValue = this._sourceFilter;
     this._sourceFilter = aValue;
 
     let ruleCount = 0;
 
     // Update the CssSheet objects.
     this.forEachSheet(function(aSheet) {
       aSheet._sheetAllowed = -1;
-      if (!aSheet.systemSheet && aSheet.sheetAllowed) {
+      if (aSheet.contentSheet && aSheet.sheetAllowed) {
         ruleCount += aSheet.ruleCount;
       }
     }, this);
 
     this._ruleCount = ruleCount;
 
     // Full update is needed because the this.processMatchedSelectors() method
     // skips UA stylesheets if the filter does not allow such sheets.
@@ -340,17 +340,17 @@ CssLogic.prototype = {
   get sheets()
   {
     if (!this._sheetsCached) {
       this._cacheSheets();
     }
 
     let sheets = [];
     this.forEachSheet(function (aSheet) {
-      if (!aSheet.systemSheet) {
+      if (aSheet.contentSheet) {
         sheets.push(aSheet);
       }
     }, this);
 
     return sheets;
   },
 
   /**
@@ -390,17 +390,17 @@ CssLogic.prototype = {
     }
 
     if (!sheetFound) {
       if (!(cacheId in this._sheets)) {
         this._sheets[cacheId] = [];
       }
 
       sheet = new CssSheet(this, aDomSheet, aIndex);
-      if (sheet.sheetAllowed && !sheet.systemSheet) {
+      if (sheet.sheetAllowed && sheet.contentSheet) {
         this._ruleCount += sheet.ruleCount;
       }
 
       this._sheets[cacheId].push(sheet);
     }
 
     return sheet;
   },
@@ -564,17 +564,17 @@ CssLogic.prototype = {
     if (!this._matchedSelectors) {
       this.processMatchedSelectors();
     }
 
     this._unmatchedSelectors = [];
 
     this.forEachSheet(function (aSheet) {
       // We do not show unmatched selectors from system stylesheets
-      if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
+      if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
         return;
       }
 
       aSheet.forEachRule(function (aRule) {
         aRule.selectors.forEach(function (aSelector) {
           if (aSelector._matchId !== this._matchId) {
             this._unmatchedSelectors.push(aSelector);
             if (aCallback) {
@@ -659,17 +659,17 @@ CssLogic.prototype = {
         }
 
         let sheet = this.getSheet(domRule.parentStyleSheet, -1);
         if (sheet._passId !== this._passId) {
           sheet.index = sheetIndex++;
           sheet._passId = this._passId;
         }
 
-        if (filter !== CssLogic.FILTER.UA && sheet.systemSheet) {
+        if (filter === CssLogic.FILTER.ALL && !sheet.contentSheet) {
           continue;
         }
 
         let rule = sheet.getRule(domRule);
         if (rule._passId === this._passId) {
           continue;
         }
 
@@ -705,17 +705,17 @@ CssLogic.prototype = {
   {
     if (!this._matchedRules) {
       this._buildMatchedRules();
     }
 
     let result = {};
 
     this.forSomeSheets(function (aSheet) {
-      if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
+      if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
         return false;
       }
 
       return aSheet.forSomeRules(function (aRule) {
         let unmatched = aRule._matchId !== this._matchId ||
                         this._ruleHasUnmatchedSelector(aRule);
         if (!unmatched) {
           return false;
@@ -860,39 +860,33 @@ CssLogic.getShortNamePath = function Css
  * @returns A localized version of the given key.
  */
 CssLogic.l10n = function(aName) CssLogic._strings.GetStringFromName(aName);
 
 XPCOMUtils.defineLazyGetter(CssLogic, "_strings", function() Services.strings
         .createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
 
 /**
- * Is the given property sheet a system (user agent) stylesheet?
+ * Is the given property sheet a content stylesheet?
  *
  * @param {CSSStyleSheet} aSheet a stylesheet
- * @return {boolean} true if the given stylesheet is a system stylesheet or
+ * @return {boolean} true if the given stylesheet is a content stylesheet,
  * false otherwise.
  */
-CssLogic.isSystemStyleSheet = function CssLogic_isSystemStyleSheet(aSheet)
+CssLogic.isContentStylesheet = function CssLogic_isContentStylesheet(aSheet)
 {
-  if (!aSheet) {
+  // All sheets with owner nodes have been included by content.
+  if (aSheet.ownerNode) {
     return true;
   }
 
-  let url = aSheet.href;
-
-  if (!url) return false;
-  if (url.length === 0) return true;
-
-  // Check for http[s]
-  if (url[0] === 'h') return false;
-  if (url.substr(0, 9) === "resource:") return true;
-  if (url.substr(0, 7) === "chrome:") return true;
-  if (url === "XPCSafeJSObjectWrapper.cpp") return true;
-  if (url.substr(0, 6) === "about:") return true;
+  // If the sheet has a CSSImportRule we need to check the parent stylesheet.
+  if (aSheet.ownerRule instanceof Ci.nsIDOMCSSImportRule) {
+    return CssLogic.isContentStylesheet(aSheet.parentStyleSheet);
+  }
 
   return false;
 };
 
 /**
  * Return a shortened version of a style sheet's source.
  *
  * @param {CSSStyleSheet} aSheet the DOM object for the style sheet.
@@ -937,17 +931,17 @@ CssLogic.shortSource = function CssLogic
  * @param {CSSStyleSheet} aDomSheet reference to a DOM CSSStyleSheet object.
  * @param {number} aIndex tells the index/position of the stylesheet within the
  * main document.
  */
 function CssSheet(aCssLogic, aDomSheet, aIndex)
 {
   this._cssLogic = aCssLogic;
   this.domSheet = aDomSheet;
-  this.index = this.systemSheet ? -100 * aIndex : aIndex;
+  this.index = this.contentSheet ? aIndex : -100 * aIndex;
 
   // Cache of the sheets href. Cached by the getter.
   this._href = null;
   // Short version of href for use in select boxes etc. Cached by getter.
   this._shortSource = null;
 
   // null for uncached.
   this._sheetAllowed = null;
@@ -955,31 +949,31 @@ function CssSheet(aCssLogic, aDomSheet, 
   // Cached CssRules from the given stylesheet.
   this._rules = {};
 
   this._ruleCount = -1;
 }
 
 CssSheet.prototype = {
   _passId: null,
-  _systemSheet: null,
+  _contentSheet: null,
   _mediaMatches: null,
 
   /**
    * Tells if the stylesheet is provided by the browser or not.
    *
-   * @return {boolean} true if this is a browser-provided stylesheet, or false
+   * @return {boolean} false if this is a browser-provided stylesheet, or true
    * otherwise.
    */
-  get systemSheet()
+  get contentSheet()
   {
-    if (this._systemSheet === null) {
-      this._systemSheet = CssLogic.isSystemStyleSheet(this.domSheet);
+    if (this._contentSheet === null) {
+      this._contentSheet = CssLogic.isContentStylesheet(this.domSheet);
     }
-    return this._systemSheet;
+    return this._contentSheet;
   },
 
   /**
    * Tells if the stylesheet is disabled or not.
    * @return {boolean} true if this stylesheet is disabled, or false otherwise.
    */
   get disabled()
   {
@@ -1043,17 +1037,17 @@ CssSheet.prototype = {
   {
     if (this._sheetAllowed !== null) {
       return this._sheetAllowed;
     }
 
     this._sheetAllowed = true;
 
     let filter = this._cssLogic.sourceFilter;
-    if (filter === CssLogic.FILTER.ALL && this.systemSheet) {
+    if (filter === CssLogic.FILTER.ALL && !this.contentSheet) {
       this._sheetAllowed = false;
     }
     if (filter !== CssLogic.FILTER.ALL && filter !== CssLogic.FILTER.UA) {
       this._sheetAllowed = (filter === this.href);
     }
 
     return this._sheetAllowed;
   },
@@ -1197,23 +1191,23 @@ function CssRule(aCssSheet, aDomRule, aE
   this._domRule = aDomRule;
 
   if (this._cssSheet) {
     // parse _domRule.selectorText on call to this.selectors
     this._selectors = null;
     this.line = this._cssSheet._cssLogic.domUtils.getRuleLine(this._domRule);
     this.source = this._cssSheet.shortSource + ":" + this.line;
     this.href = this._cssSheet.href;
-    this.systemRule = this._cssSheet.systemSheet;
+    this.contentRule = this._cssSheet.contentSheet;
   } else if (aElement) {
     this._selectors = [ new CssSelector(this, "@element.style") ];
     this.line = -1;
     this.source = CssLogic.l10n("rule.sourceElement");
     this.href = "#";
-    this.systemRule = false;
+    this.contentRule = true;
     this.sourceElement = aElement;
   }
 }
 
 CssRule.prototype = {
   _passId: null,
 
   /**
@@ -1391,22 +1385,22 @@ CssSelector.prototype = {
   get href()
   {
     return this._cssRule.href;
   },
 
   /**
    * Check if the selector comes from a browser-provided stylesheet.
    *
-   * @return {boolean} true if the selector comes from a browser-provided
+   * @return {boolean} true if the selector comes from a content-provided
    * stylesheet, or false otherwise.
    */
-  get systemRule()
+  get contentRule()
   {
-    return this._cssRule.systemRule;
+    return this._cssRule.contentRule;
   },
 
   /**
    * Check if the parent stylesheet is allowed by the CssLogic.sourceFilter.
    *
    * @return {boolean} true if the parent stylesheet is allowed by the current
    * sourceFilter, or false otherwise.
    */
@@ -1789,22 +1783,22 @@ function CssSelectorInfo(aSelector, aPro
   /* Score prefix:
   0 UA normal property
   1 UA important property
   2 normal property
   3 inline (element.style)
   4 important
   5 inline important
   */
-  let scorePrefix = this.systemRule ? 0 : 2;
+  let scorePrefix = this.contentRule ? 2 : 0;
   if (this.elementStyle) {
     scorePrefix++;
   }
   if (this.important) {
-    scorePrefix += this.systemRule ? 1 : 2;
+    scorePrefix += this.contentRule ? 2 : 1;
   }
 
   this.specificityScore = "" + scorePrefix + this.specificity.ids +
       this.specificity.classes + this.specificity.tags;
 }
 
 CssSelectorInfo.prototype = {
   /**
@@ -1897,32 +1891,32 @@ CssSelectorInfo.prototype = {
   },
 
   /**
    * Check if the selector comes from a browser-provided stylesheet.
    *
    * @return {boolean} true if the selector comes from a browser-provided
    * stylesheet, or false otherwise.
    */
-  get systemRule()
+  get contentRule()
   {
-    return this.selector.systemRule;
+    return this.selector.contentRule;
   },
 
   /**
    * Compare the current CssSelectorInfo instance to another instance, based on
    * specificity information.
    *
    * @param {CssSelectorInfo} aThat The instance to compare ourselves against.
    * @return number -1, 0, 1 depending on how aThat compares with this.
    */
   compareTo: function CssSelectorInfo_compareTo(aThat)
   {
-    if (this.systemRule && !aThat.systemRule) return 1;
-    if (!this.systemRule && aThat.systemRule) return -1;
+    if (!this.contentRule && aThat.contentRule) return 1;
+    if (this.contentRule && !aThat.contentRule) return -1;
 
     if (this.elementStyle && !aThat.elementStyle) {
       if (!this.important && aThat.important) return 1;
       else return -1;
     }
 
     if (!this.elementStyle && aThat.elementStyle) {
       if (this.important && !aThat.important) return -1;
--- a/browser/devtools/styleinspector/CssRuleView.jsm
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -33,17 +33,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-"use strict"
+"use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
@@ -176,18 +176,18 @@ ElementStyle.prototype = {
     var domRules = this.domUtils.getCSSStyleRules(aElement);
 
     // getCSStyleRules returns ordered from least-specific to
     // most-specific.
     for (let i = domRules.Count() - 1; i >= 0; i--) {
       let domRule = domRules.GetElementAt(i);
 
       // XXX: Optionally provide access to system sheets.
-      let systemSheet = CssLogic.isSystemStyleSheet(domRule.parentStyleSheet);
-      if (systemSheet) {
+      let contentSheet = CssLogic.isContentStylesheet(domRule.parentStyleSheet);
+      if (!contentSheet) {
         continue;
       }
 
       if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
         continue;
       }
 
       this._maybeAddRule({
@@ -319,17 +319,17 @@ ElementStyle.prototype = {
       dirty = computedProp._overriddenDirty || dirty;
       delete computedProp._overriddenDirty;
     }
 
     dirty = (!!aProp.overridden != overridden) || dirty;
     aProp.overridden = overridden;
     return dirty;
   }
-}
+};
 
 /**
  * A single style rule or declaration.
  *
  * @param {ElementStyle} aElementStyle
  *        The ElementStyle to which this rule belongs.
  * @param {object} aOptions
  *        The information used to construct this rule.  Properties include:
@@ -353,37 +353,55 @@ function Rule(aElementStyle, aOptions)
 }
 
 Rule.prototype = {
   get title()
   {
     if (this._title) {
       return this._title;
     }
-    let sheet = this.domRule ? this.domRule.parentStyleSheet : null;
-    this._title = CssLogic.shortSource(sheet);
+    this._title = CssLogic.shortSource(this.sheet);
     if (this.domRule) {
-      let line = this.elementStyle.domUtils.getRuleLine(this.domRule);
-      this._title += ":" + line;
+      this._title += ":" + this.ruleLine;
     }
 
     if (this.inherited) {
       let eltText = this.inherited.tagName.toLowerCase();
       if (this.inherited.id) {
         eltText += "#" + this.inherited.id;
       }
       let args = [eltText, this._title];
       this._title = CssLogic._strings.formatStringFromName("rule.inheritedSource",
                                                            args, args.length);
     }
 
     return this._title;
   },
 
   /**
+   * The rule's stylesheet.
+   */
+  get sheet()
+  {
+    return this.domRule ? this.domRule.parentStyleSheet : null;
+  },
+
+  /**
+   * The rule's line within a stylesheet
+   */
+  get ruleLine()
+  {
+    if (!this.sheet) {
+      // No stylesheet, no ruleLine
+      return null;
+    }
+    return this.elementStyle.domUtils.getRuleLine(this.domRule);
+  },
+
+  /**
    * Create a new TextProperty to include in the rule.
    *
    * @param {string} aName
    *        The text property name (such as "background" or "border-top").
    * @param {string} aValue
    *        The property's value (not including priority).
    * @param {string} aPriority
    *        The property's priority (either "important" or an empty string).
@@ -525,17 +543,17 @@ Rule.prototype = {
 
     for each (let prop in disabledProps) {
       let textProp = new TextProperty(this, prop.name,
                                       prop.value, prop.priority);
       textProp.enabled = false;
       this.textProps.push(textProp);
     }
   },
-}
+};
 
 /**
  * A single property in a rule's cssText.
  *
  * @param {Rule} aRule
  *        The rule this TextProperty came from.
  * @param {string} aName
  *        The text property name (such as "background" or "border-top").
@@ -613,17 +631,17 @@ TextProperty.prototype = {
     this.rule.setPropertyEnabled(this, aValue);
     this.updateEditor();
   },
 
   remove: function TextProperty_remove()
   {
     this.rule.removeProperty(this);
   }
-}
+};
 
 
 /**
  * View hierarchy mostly follows the model hierarchy.
  *
  * CssRuleView:
  *   Owns an ElementStyle and creates a list of RuleEditors for its
  *    Rules.
@@ -638,29 +656,28 @@ TextProperty.prototype = {
  *   Can mark a property disabled or enabled.
  */
 
 /**
  * CssRuleView is a view of the style rules and declarations that
  * apply to a given element.  After construction, the 'element'
  * property will be available with the user interface.
  *
- * @param Document aDocument
+ * @param Document aDoc
  *        The document that will contain the rule view.
  * @param object aStore
  *        The CSS rule view can use this object to store metadata
  *        that might outlast the rule view, particularly the current
  *        set of disabled properties.
  * @constructor
  */
 function CssRuleView(aDoc, aStore)
 {
   this.doc = aDoc;
   this.store = aStore;
-
   this.element = this.doc.createElementNS(XUL_NS, "vbox");
   this.element.setAttribute("tabindex", "0");
   this.element.classList.add("ruleview");
   this.element.flex = 1;
 }
 
 CssRuleView.prototype = {
   // The element that we're inspecting.
@@ -763,16 +780,24 @@ RuleEditor.prototype = {
     // span to be placed absolutely against.
     this.element.style.position = "relative";
 
     // Add the source link.
     let source = createChild(this.element, "div", {
       class: "ruleview-rule-source",
       textContent: this.rule.title
     });
+    source.addEventListener("click", function() {
+      let rule = this.rule;
+      let evt = this.doc.createEvent("CustomEvent");
+      evt.initCustomEvent("CssRuleViewCSSLinkClicked", true, false, {
+        rule: rule,
+      });
+      this.element.dispatchEvent(evt);
+    }.bind(this));
 
     let code = createChild(this.element, "div", {
       class: "ruleview-code"
     });
 
     let header = createChild(code, "div", {});
 
     let selectors = createChild(header, "span", {
@@ -1089,18 +1114,16 @@ TextPropertyEditor.prototype = {
    *
    * @param {string} aValue
    *        The value from the text editor.
    * @return an object with 'value' and 'priority' properties.
    */
   _parseValue: function TextPropertyEditor_parseValue(aValue)
   {
     let pieces = aValue.split("!", 2);
-    let value = pieces[0];
-    let priority = pieces.length > 1 ? pieces[1] : "";
     return {
       value: pieces[0].trim(),
       priority: (pieces.length > 1 ? pieces[1].trim() : "")
     };
   },
 
   /**
    * Called when a value editor closes.  If the user pressed escape,
--- a/browser/devtools/styleinspector/csshtmltree.xul
+++ b/browser/devtools/styleinspector/csshtmltree.xul
@@ -109,17 +109,17 @@ To visually debug the templates without 
   <div id="templateMatchedSelectors">
     <table>
       <loop foreach="selector in ${matchedSelectorViews}">
         <tr>
           <td dir="ltr" class="rule-text ${selector.statusClass}">
             ${selector.humanReadableText(__element)}
           </td>
           <td class="rule-link">
-            <a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
+            <a target="_blank" onclick="${selector.openStyleEditor}" class="link"
                title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
           </td>
         </tr>
       </loop>
     </table>
   </div>
 </div>
 
--- a/browser/devtools/styleinspector/test/Makefile.in
+++ b/browser/devtools/styleinspector/test/Makefile.in
@@ -54,20 +54,28 @@ include $(topsrcdir)/config/rules.mk
   browser_styleinspector_bug_689759_no_results_placeholder.js \
   browser_bug_692400_element_style.js \
   browser_csslogic_inherited.js \
   browser_ruleview_editor.js \
   browser_ruleview_inherit.js \
   browser_ruleview_manipulation.js \
   browser_ruleview_override.js \
   browser_ruleview_ui.js \
+  browser_bug705707_is_content_stylesheet.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_bug683672.html \
+  browser_bug705707_is_content_stylesheet.html \
+  browser_bug705707_is_content_stylesheet_imported.css \
+  browser_bug705707_is_content_stylesheet_imported2.css \
+  browser_bug705707_is_content_stylesheet_linked.css \
+  browser_bug705707_is_content_stylesheet_script.css \
+  browser_bug705707_is_content_stylesheet.xul \
+  browser_bug705707_is_content_stylesheet_xul.css \
   $(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 
 libs:: $(_BROWSER_TEST_PAGES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+  <title>test</title>
+
+  <link href="./browser_bug705707_is_content_stylesheet_linked.css" rel="stylesheet" type="text/css">
+
+  <script>
+    // Load script.css
+    function loadCSS() {
+      var link = document.createElement('link');
+      link.rel = 'stylesheet';
+      link.type = 'text/css';
+      link.href = "./browser_bug705707_is_content_stylesheet_script.css";
+      document.getElementsByTagName('head')[0].appendChild(link);
+    }
+  </script>
+
+  <style>
+    table {
+      border: 1px solid #000;
+    }
+  </style>
+</head>
+<body onload="loadCSS();">
+  <table id="target">
+    <tr>
+      <td>
+        <h3>Simple test</h3>
+      </td>
+    </tr>
+  </table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet.js
@@ -0,0 +1,100 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the correct stylesheets origins are identified in HTML & XUL
+// stylesheets
+
+let doc;
+
+const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
+                 "test/browser_bug705707_is_content_stylesheet.html";
+const TEST_URI2 = "http://example.com/browser/browser/devtools/styleinspector/" +
+                 "test/browser_bug705707_is_content_stylesheet.xul";
+const XUL_URI = Cc["@mozilla.org/network/io-service;1"]
+                .getService(Ci.nsIIOService)
+                .newURI(TEST_URI2, null, null);
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/CssLogic.jsm", tempScope);
+let CssLogic = tempScope.CssLogic;
+
+function test()
+{
+  waitForExplicitFinish();
+  addTab(TEST_URI);
+  browser.addEventListener("load", htmlLoaded, true);
+}
+
+function htmlLoaded()
+{
+  browser.removeEventListener("load", htmlLoaded, true);
+  doc = content.document;
+  testFromHTML()
+}
+
+function testFromHTML()
+{
+  let target = doc.querySelector("#target");
+
+  executeSoon(function() {
+    checkSheets(target);
+    gBrowser.removeCurrentTab();
+    openXUL();
+  });
+}
+
+function openXUL()
+{
+  Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager)
+    .add(XUL_URI, 'allowXULXBL', Ci.nsIPermissionManager.ALLOW_ACTION);
+  addTab(TEST_URI2);
+  browser.addEventListener("load", xulLoaded, true);
+}
+
+function xulLoaded()
+{
+  browser.removeEventListener("load", xulLoaded, true);
+  doc = content.document;
+  testFromXUL()
+}
+
+function testFromXUL()
+{
+  let target = doc.querySelector("#target");
+
+  executeSoon(function() {
+    checkSheets(target);
+    finishUp();
+  });
+}
+
+function checkSheets(aTarget)
+{
+  let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
+      .getService(Ci.inIDOMUtils);
+  let domRules = domUtils.getCSSStyleRules(aTarget);
+
+  for (let i = 0, n = domRules.Count(); i < n; i++) {
+    let domRule = domRules.GetElementAt(i);
+    let sheet = domRule.parentStyleSheet;
+    let isContentSheet = CssLogic.isContentStylesheet(sheet);
+
+    if (!sheet.href ||
+        /browser_bug705707_is_content_stylesheet_/.test(sheet.href)) {
+      ok(isContentSheet, sheet.href + " identified as content stylesheet");
+    } else {
+      ok(!isContentSheet, sheet.href + " identified as non-content stylesheet");
+    }
+  }
+}
+
+function finishUp()
+{
+  info("finishing up");
+  Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager)
+    .add(XUL_URI, 'allowXULXBL', Ci.nsIPermissionManager.DENY_ACTION);
+  doc = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet.xul
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/xul.css" type="text/css"?>
+<?xml-stylesheet href="./browser_bug705707_is_content_stylesheet_xul.css"
+                 type="text/css"?>
+<!DOCTYPE window>
+<window id="testwindow" xmlns:html="http://www.w3.org/1999/xhtml"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <label id="target" value="Simple XUL document" />
+</window>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet_imported.css
@@ -0,0 +1,5 @@
+@import url("./browser_bug705707_is_content_stylesheet_imported2.css");
+
+#target {
+  text-decoration: underline;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet_imported2.css
@@ -0,0 +1,3 @@
+#target {
+  text-decoration: underline;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet_linked.css
@@ -0,0 +1,3 @@
+table  {
+  border-collapse: collapse;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet_script.css
@@ -0,0 +1,5 @@
+@import url("./browser_bug705707_is_content_stylesheet_imported.css");
+
+table  {
+  opacity: 1;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug705707_is_content_stylesheet_xul.css
@@ -0,0 +1,3 @@
+#target {
+  font-size: 200px;
+}
--- a/browser/devtools/webconsole/GcliCommands.jsm
+++ b/browser/devtools/webconsole/GcliCommands.jsm
@@ -121,16 +121,50 @@ gcli.addCommand({
     }
   ],
   exec: function Command_inspect(args, context) {
     let document = context.environment.chromeDocument;
     document.defaultView.InspectorUI.openInspectorUI(args.node);
   }
 });
 
+/**
+ * 'edit' command
+ */
+gcli.addCommand({
+  name: "edit",
+  description: gcli.lookup("editDesc"),
+  manual: gcli.lookup("editManual"),
+  params: [
+     {
+       name: 'resource',
+       type: {
+         name: 'resource',
+         include: 'text/css'
+       },
+       description: gcli.lookup("editResourceDesc")
+     },
+     {
+       name: "line",
+       defaultValue: 1,
+       type: {
+         name: "number",
+         min: 1,
+         step: 10
+       },
+       description: gcli.lookup("editLineToJumpToDesc")
+     }
+   ],
+   exec: function(args, context) {
+     let hud = HUDService.getHudReferenceById(context.environment.hudId);
+     let StyleEditor = hud.gcliterm.document.defaultView.StyleEditor;
+     StyleEditor.openChrome(args.resource.element, args.line);
+   }
+});
+
 let breakpoints = [];
 
 /**
  * 'break' command
  */
 gcli.addCommand({
   name: "break",
   description: gcli.lookup("breakDesc"),
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -145,19 +145,16 @@
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
-#ifdef MOZ_B2G_BT
-@BINPATH@/components/dom_bluetooth.xpt
-#endif
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -124,8 +124,28 @@ breakdelBreakidDesc=Index of breakpoint
 # LOCALIZATION NOTE (breakdelRemoved) Used in the output of the 'break del'
 # command to explain that a breakpoint was removed.
 breakdelRemoved=Breakpoint removed
 
 # LOCALIZATION NOTE (consolecloseDesc) A very short description of the
 # 'console close' command. This string is designed to be shown in a menu
 # alongside the command name, which is why it should be as short as possible.
 consolecloseDesc=Close the console
+
+# LOCALIZATION NOTE (editDesc) A very short description of the 'edit'
+# command. See editManual for a fuller description of what it does. This
+# string is designed to be shown in a menu alongside the command name, which
+# is why it should be as short as possible.
+editDesc=Tweak a page resource
+
+# LOCALIZATION NOTE (editManual) A fuller description of the 'edit' command,
+# displayed when the user asks for help on what it does.
+editManual=Edit one of the resources that is part of this page (or maybe any generic web resource?)
+
+# LOCALIZATION NOTE (editResourceDesc) A very short string to describe the
+# 'resource' parameter to the 'edit' command, which is displayed in a dialog
+# when the user is using this command.
+editResourceDesc=URL to edit
+
+# LOCALIZATION NOTE (editLineToJumpToDesc) A very short string to describe the
+# 'line' parameter to the 'edit' command, which is displayed in a dialog
+# when the user is using this command.
+editLineToJumpToDesc=Line to jump to
--- a/browser/makefiles.sh
+++ b/browser/makefiles.sh
@@ -83,16 +83,22 @@ browser/fuel/public/Makefile
 browser/fuel/src/Makefile
 browser/installer/Makefile
 browser/locales/Makefile
 browser/modules/Makefile
 browser/themes/Makefile
 $MOZ_BRANDING_DIRECTORY/Makefile
 $MOZ_BRANDING_DIRECTORY/content/Makefile
 $MOZ_BRANDING_DIRECTORY/locales/Makefile
+toolkit/locales/Makefile
+extensions/spellcheck/locales/Makefile
+intl/locales/Makefile
+netwerk/locales/Makefile
+dom/locales/Makefile
+security/manager/locales/Makefile
 "
 
 if [ "$MOZ_SAFE_BROWSING" ]; then
   add_makefiles "
     browser/components/safebrowsing/Makefile
   "
 fi
 
--- a/browser/themes/gnomestripe/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/devtools/csshtmltree.css
@@ -63,16 +63,19 @@
   color: #0091ff;
 }
 .link,
 .helplink,
 .link:visited,
 .helplink:visited {
   text-decoration: none;
 }
+.link:hover {
+  text-decoration: underline;
+}
 
 .helplink {
   display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
@@ -130,16 +133,17 @@
 .property-view-hidden,
 .property-content-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
+  cursor: pointer;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
   padding: 0;
   -moz-padding-start: 20px;
 }
@@ -195,17 +199,23 @@
  */
 
 .ruleview {
   background-color: #FFF;
 }
 
 .ruleview-rule-source {
   background-color: -moz-dialog;
+  color: #0091ff;
   padding: 2px 5px;
+  cursor: pointer;
+}
+
+.ruleview-rule-source:hover {
+  text-decoration: underline;
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
 .ruleview-ruleopen {
   -moz-padding-end: 5px;
--- a/browser/themes/pinstripe/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/devtools/csshtmltree.css
@@ -63,16 +63,19 @@
   color: #0091ff;
 }
 .link,
 .helplink,
 .link:visited,
 .helplink:visited {
   text-decoration: none;
 }
+.link:hover {
+  text-decoration: underline;
+}
 
 .helplink {
   display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
@@ -132,16 +135,17 @@
 .property-view-hidden,
 .property-content-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
+  cursor: pointer;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
   padding: 0;
   -moz-padding-start: 20px;
 }
@@ -197,17 +201,23 @@
  */
 
 .ruleview {
   background-color: #FFF;
 }
 
 .ruleview-rule-source {
   background-color: -moz-dialog;
+  color: #0091ff;
   padding: 2px 5px;
+  cursor: pointer;
+}
+
+.ruleview-rule-source:hover {
+  text-decoration: underline;
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
 .ruleview-ruleopen {
   -moz-padding-end: 5px;
--- a/browser/themes/winstripe/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/devtools/csshtmltree.css
@@ -62,16 +62,19 @@
   color: #0091ff;
 }
 .link,
 .helplink,
 .link:visited,
 .helplink:visited {
   text-decoration: none;
 }
+.link:hover {
+  text-decoration: underline;
+}
 
 .helplink {
   display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
@@ -130,16 +133,17 @@
 .property-view-hidden,
 .property-content-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
+  cursor: pointer;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
   padding: 0;
   -moz-padding-start: 20px;
 }
@@ -195,17 +199,23 @@
  */
 
 .ruleview {
   background-color: #FFF;
 }
 
 .ruleview-rule-source {
   background-color: -moz-dialog;
+  color: #0091ff;
   padding: 2px 5px;
+  cursor: pointer;
+}
+
+.ruleview-rule-source:hover {
+  text-decoration: underline;
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
 .ruleview-ruleopen {
   -moz-padding-end: 5px;
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -79,17 +79,17 @@ endif
 APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
 APP_INI_DEPS += $(DEPTH)/config/buildid
 
 DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DAPP_BUILDID=$(APP_BUILDID)
 
 DEFINES += -DMOZ_APP_VERSION="$(MOZ_APP_VERSION)"
 APP_INI_DEPS += $(DEPTH)/config/autoconf.mk
 
-MOZ_SOURCE_STAMP ?= $(firstword $(shell hg -R $(topsrcdir)/$(MOZ_BUILD_APP)/.. parent --template="{node|short}\n" 2>/dev/null))
+MOZ_SOURCE_STAMP := $(firstword $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg parent --template="{node|short}\n" 2>/dev/null))
 ifdef MOZ_SOURCE_STAMP
 DEFINES += -DMOZ_SOURCE_STAMP="$(MOZ_SOURCE_STAMP)"
 endif
 
 _dollar=$$
 SOURCE_REPO := $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg showconfig paths.default 2>/dev/null | head -n1 | sed -e "s/^ssh:/http:/" -e "s/\/$(_dollar)//" )
 ifdef SOURCE_REPO
 DEFINES += -DMOZ_SOURCE_REPO="$(SOURCE_REPO)"
new file mode 100644
--- /dev/null
+++ b/build/autoconf/compiler-opts.m4
@@ -0,0 +1,13 @@
+dnl Add compiler specific options
+
+AC_DEFUN([MOZ_COMPILER_OPTS],
+[
+if test "$CLANG_CXX"; then
+    ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
+    ## returned by C functions. This is possible because we use knowledge about the ABI
+    ## to typedef it to a C type with the same layout when the headers are included
+    ## from C.
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-return-type-c-linkage"
+fi
+])
+
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -1,10 +1,23 @@
 #!/usr/bin/python
 
+# The directories end up in the debug info, so the easy way of getting
+# a reproducible build is to run it in a know absolute directory.
+# We use a directory in /builds/slave because the mozilla infrastructure
+# cleans it up automatically.
+base_dir = "/builds/slave/moz-toolschain"
+
+source_dir = base_dir + "/src"
+build_dir  = base_dir + "/build"
+aux_inst_dir = build_dir + '/aux_inst'
+old_make = aux_inst_dir + '/bin/make'
+
+##############################################
+
 import urllib
 import os
 import os.path
 import shutil
 import tarfile
 import subprocess
 
 def download_uri(uri):
@@ -28,27 +41,31 @@ def run_in(path, args):
     check_run(args)
     os.chdir(d)
 
 def patch(patch, plevel, srcdir):
     patch = os.path.realpath(patch)
     check_run(['patch', '-d', srcdir, '-p%s' % plevel, '-i', patch, '--fuzz=0',
                '-s'])
 
-def build_package(package_source_dir, package_build_dir, configure_args):
+def build_package(package_source_dir, package_build_dir, configure_args,
+                   make = old_make):
     os.mkdir(package_build_dir)
     run_in(package_build_dir,
            ["%s/configure" % package_source_dir] + configure_args)
-    run_in(package_build_dir, ["make", "-j8"])
-    run_in(package_build_dir, ["make", "install"])
+    run_in(package_build_dir, [make, "-j8"])
+    run_in(package_build_dir, [make, "install"])
 
-def build_tar(base_dir, tar_inst_dir):
+def build_aux_tools(base_dir):
+    make_build_dir = base_dir + '/make_build'
+    build_package(make_source_dir, make_build_dir,
+                  ["--prefix=%s" % aux_inst_dir], "make")
     tar_build_dir = base_dir + '/tar_build'
     build_package(tar_source_dir, tar_build_dir,
-                  ["--prefix=%s" % tar_inst_dir])
+                  ["--prefix=%s" % aux_inst_dir])
 
 def with_env(env, f):
     old_env = os.environ.copy()
     os.environ.update(env)
     f()
     os.environ.clear()
     os.environ.update(old_env)
 
@@ -128,94 +145,90 @@ def build_one_stage_aux(stage_dir, is_st
 
 def build_tar_package(tar, name, base, directory):
     name = os.path.realpath(name)
     run_in(base, [tar, "-cf", name, "--mtime=2012-01-01", "--owner=root",
                   directory])
 
 ##############################################
 
-# The directories end up in the debug info, so the easy way of getting
-# a reproducible build is to run it in a know absolute directory.
-# We use a directory in /builds/slave because the mozilla infrastructure
-# cleans it up automatically.
-base_dir = "/builds/slave/moz-toolschain"
-
-source_dir = base_dir + "/src"
-build_dir  = base_dir + "/build"
-
 def build_source_dir(prefix, version):
     return source_dir + '/' + prefix + version
 
 binutils_version = "2.21.1"
-glibc_version = "2.12.2" #FIXME: should probably use 2.5.1
+glibc_version = "2.5.1"
 tar_version = "1.26"
+make_version = "3.81"
 gcc_version = "4.5.2"
 mpfr_version = "2.4.2"
 gmp_version = "5.0.1"
 mpc_version = "0.8.1"
 
 binutils_source_uri = "http://ftp.gnu.org/gnu/binutils/binutils-%sa.tar.bz2" % \
     binutils_version
 glibc_source_uri = "http://ftp.gnu.org/gnu/glibc/glibc-%s.tar.bz2" % \
     glibc_version
 tar_source_uri = "http://ftp.gnu.org/gnu/tar/tar-%s.tar.bz2" % \
     tar_version
+make_source_uri = "http://ftp.gnu.org/gnu/make/make-%s.tar.bz2" % \
+    make_version
 gcc_source_uri = "http://ftp.gnu.org/gnu/gcc/gcc-%s/gcc-%s.tar.bz2" % \
     (gcc_version, gcc_version)
 mpfr_source_uri = "http://www.mpfr.org/mpfr-%s/mpfr-%s.tar.bz2" % \
     (mpfr_version, mpfr_version)
 gmp_source_uri = "http://ftp.gnu.org/gnu/gmp/gmp-%s.tar.bz2" % gmp_version
 mpc_source_uri = "http://www.multiprecision.org/mpc/download/mpc-%s.tar.gz" % \
     mpc_version
 
 binutils_source_tar = download_uri(binutils_source_uri)
 glibc_source_tar = download_uri(glibc_source_uri)
 tar_source_tar = download_uri(tar_source_uri)
+make_source_tar = download_uri(make_source_uri)
 mpc_source_tar = download_uri(mpc_source_uri)
 mpfr_source_tar = download_uri(mpfr_source_uri)
 gmp_source_tar = download_uri(gmp_source_uri)
 gcc_source_tar = download_uri(gcc_source_uri)
 
 binutils_source_dir  = build_source_dir('binutils-', binutils_version)
 glibc_source_dir  = build_source_dir('glibc-', glibc_version)
 tar_source_dir  = build_source_dir('tar-', tar_version)
+make_source_dir  = build_source_dir('make-', make_version)
 mpc_source_dir  = build_source_dir('mpc-', mpc_version)
 mpfr_source_dir = build_source_dir('mpfr-', mpfr_version)
 gmp_source_dir  = build_source_dir('gmp-', gmp_version)
 gcc_source_dir  = build_source_dir('gcc-', gcc_version)
 
 if not os.path.exists(source_dir):
     os.makedirs(source_dir)
     extract(binutils_source_tar, source_dir)
     patch('binutils-deterministic.patch', 1, binutils_source_dir)
     extract(glibc_source_tar, source_dir)
     patch('glibc-deterministic.patch', 1, glibc_source_dir)
     run_in(glibc_source_dir, ["autoconf"])
     extract(tar_source_tar, source_dir)
+    extract(make_source_tar, source_dir)
     extract(mpc_source_tar, source_dir)
     extract(mpfr_source_tar, source_dir)
     extract(gmp_source_tar, source_dir)
     extract(gcc_source_tar, source_dir)
     patch('plugin_finish_decl.diff', 0, gcc_source_dir)
     patch('pr49911.diff', 1, gcc_source_dir)
     patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
 
 if os.path.exists(build_dir):
     shutil.rmtree(build_dir)
 os.makedirs(build_dir)
 
-tar_inst_dir = build_dir + '/tar_inst'
-build_tar(build_dir, tar_inst_dir)
+build_aux_tools(build_dir)
 
 stage1_dir = build_dir + '/stage1'
 build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir, True)
 
 stage1_tool_inst_dir = stage1_dir + '/inst'
 stage2_dir = build_dir + '/stage2'
-build_one_stage({"CC"     : stage1_tool_inst_dir + "/bin/gcc",
+build_one_stage({"CC"     : stage1_tool_inst_dir + "/bin/gcc -fgnu89-inline",
                  "CXX"    : stage1_tool_inst_dir + "/bin/g++",
                  "AR"     : stage1_tool_inst_dir + "/bin/ar",
                  "RANLIB" : "true" },
                 stage2_dir, False)
 
-build_tar_package(tar_inst_dir + "/bin/tar",
+build_tar_package(aux_inst_dir + "/bin/tar",
                   "toolchain.tar", stage2_dir, "inst")
--- a/build/unix/build-toolchain/glibc-deterministic.patch
+++ b/build/unix/build-toolchain/glibc-deterministic.patch
@@ -1,36 +1,99 @@
 diff -ru a/configure.in b/configure.in
 --- a/configure.in	2011-01-17 23:34:07.000000000 -0500
 +++ b/configure.in	2012-01-25 20:40:27.919485606 -0500
-@@ -2230,6 +2230,7 @@
+@@ -841,14 +841,6 @@
+ LIBC_PROG_BINUTILS
+ AC_SUBST(MIG)dnl Needed by sysdeps/mach/configure.in
+ 
+-# Accept binutils 2.13 or newer.
+-AC_CHECK_PROG_VER(AS, $AS, --version,
+-		  [GNU assembler.* \([0-9]*\.[0-9.]*\)],
+-		  [2.1[3-9]*], AS=: critic_missing="$critic_missing as")
+-AC_CHECK_PROG_VER(LD, $LD, --version,
+-		  [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
+-		  [2.1[3-9]*], LD=: critic_missing="$critic_missing ld")
+-
+ # We need the physical current working directory.  We cannot use the
+ # "pwd -P" shell builtin since that's not portable.  Instead we try to
+ # find a pwd binary.  Note that assigning to the PWD environment
+@@ -2175,6 +2167,7 @@
  fi
  AC_SUBST(old_glibc_headers)
  
 +libc_cv_slibdir=${prefix}/lib64
  AC_SUBST(libc_cv_slibdir)
  AC_SUBST(libc_cv_localedir)
  AC_SUBST(libc_cv_sysconfdir)
 diff -ru a/csu/Makefile b/csu/Makefile
 --- a/csu/Makefile	2011-01-17 23:34:07.000000000 -0500
 +++ b/csu/Makefile	2012-01-23 13:58:28.957792633 -0500
-@@ -234,8 +234,7 @@
+@@ -223,8 +223,7 @@
  		   if [ -z "$$os" ]; then \
  		     os=Linux; \
  		   fi; \
 -		   printf '"Compiled on a %s %s system on %s.\\n"\n' \
 -			  "$$os" "$$version" "`date +%Y-%m-%d`";; \
 +                   ;; \
  	   *) ;; \
  	 esac; \
  	 files="$(all-Banner-files)";				\
+diff -ru a/elf/Makefile b/elf/Makefile
+--- a/elf/Makefile	2008-10-31 16:35:11.000000000 -0400
++++ b/elf/Makefile	2012-02-16 12:20:00.038593752 -0500
+@@ -295,18 +295,11 @@
+ z-now-yes = -Wl,-z,now
+ 
+ $(objpfx)ld.so: $(objpfx)librtld.os $(ld-map)
+-	@rm -f $@.lds
+-	$(LINK.o) -nostdlib -nostartfiles -shared $(z-now-$(bind-now))	\
+-		  $(LDFLAGS-rtld) -Wl,-z,defs -Wl,--verbose 2>&1 |	\
+-		  LC_ALL=C \
+-		  sed -e '/^=========/,/^=========/!d;/^=========/d'	\
+-		      -e 's/\. = 0 + SIZEOF_HEADERS;/& _begin = . - SIZEOF_HEADERS;/' \
+-		  > $@.lds
+ 	$(LINK.o) -nostdlib -nostartfiles -shared -o $@			\
+ 		  $(LDFLAGS-rtld) -Wl,-z,defs $(z-now-$(bind-now))	\
+ 		  $(filter-out $(map-file),$^) $(load-map-file)		\
+-		  -Wl,-soname=$(rtld-installed-name) -T $@.lds
+-	rm -f $@.lds
++		  -Wl,-soname=$(rtld-installed-name)			\
++		  -Wl,-defsym=_begin=0
+ 
+ # interp.c exists just to get this string into the libraries.
+ CFLAGS-interp.c = -D'RUNTIME_LINKER="$(slibdir)/$(rtld-installed-name)"' \
+diff -ru a/localedata/Makefile b/localedata/Makefile
+--- a/localedata/Makefile	2006-04-26 01:14:03.000000000 -0400
++++ b/localedata/Makefile	2012-02-17 10:31:24.592345047 -0500
+@@ -113,7 +113,7 @@
+ 	$(make-target-directory)
+ 	rm -f $(@:.gz=) $@
+ 	$(INSTALL_DATA) $< $(@:.gz=)
+-	gzip -9 $(@:.gz=)
++	gzip -9n $(@:.gz=)
+ 
+ # Install the locale source files in the appropriate directory.
+ $(inst_i18ndir)/locales/%: locales/% $(+force); $(do-install)
+diff -ru a/Makeconfig b/Makeconfig
+--- a/Makeconfig	2006-07-10 17:42:27.000000000 -0400
++++ b/Makeconfig	2012-02-17 08:28:31.859584817 -0500
+@@ -674,7 +674,7 @@
+ 	   $(foreach lib,$(libof-$(basename $(@F))) \
+ 		         $(libof-$(<F)) $(libof-$(@F)),$(CPPFLAGS-$(lib))) \
+ 	   $(CPPFLAGS-$(<F)) $(CPPFLAGS-$(@F)) $(CPPFLAGS-$(basename $(@F)))
+-override CFLAGS	= -std=gnu99 \
++override CFLAGS	= -std=gnu99 -fgnu89-inline \
+ 		  $(filter-out %frame-pointer,$(+cflags)) $(+gccwarn-c) \
+ 		  $(sysdep-CFLAGS) $(CFLAGS-$(suffix $@)) $(CFLAGS-$(<F)) \
+ 		  $(CFLAGS-$(@F))
 diff -ru a/Makerules b/Makerules
 --- a/Makerules	2011-01-17 23:34:07.000000000 -0500
 +++ b/Makerules	2012-01-30 08:47:56.565068903 -0500
-@@ -992,9 +992,9 @@
+@@ -977,9 +977,9 @@
  	 echo '   Use the shared library, but some functions are only in';\
  	 echo '   the static library, so try that secondarily.  */';\
  	 cat $<; \
 -	 echo 'GROUP ( $(slibdir)/libc.so$(libc.so-version)' \
 -	      '$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)$(libc-name))'\
 -	      ' AS_NEEDED (' $(slibdir)/$(rtld-installed-name) ') )' \
 +	 echo 'GROUP ( libc.so$(libc.so-version)' \
 +	      '$(patsubst %,$(libtype.oS),$(libprefix)$(libc-name))'\
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -52,17 +52,16 @@ MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNA
 MOZ_APP_BASENAME = @MOZ_APP_BASENAME@
 MOZ_APP_VENDOR = @MOZ_APP_VENDOR@
 MOZ_APP_PROFILE = @MOZ_APP_PROFILE@
 MOZ_APP_ID = @MOZ_APP_ID@
 MOZ_PROFILE_MIGRATOR = @MOZ_PROFILE_MIGRATOR@
 MOZ_EXTENSION_MANAGER = @MOZ_EXTENSION_MANAGER@
 MOZ_APP_UA_NAME = @MOZ_APP_UA_NAME@
 MOZ_APP_VERSION = @MOZ_APP_VERSION@
-MOZ_UA_BUILDID = @MOZ_UA_BUILDID@
 MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@
 MOZ_APP_STATIC_INI = @MOZ_APP_STATIC_INI@
 
 MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@
 
 prefix		= @prefix@
 exec_prefix	= @exec_prefix@
 bindir		= @bindir@
@@ -176,16 +175,17 @@ VPX_AS_CONVERSION = @VPX_AS_CONVERSION@
 VPX_ASM_SUFFIX = @VPX_ASM_SUFFIX@
 VPX_X86_ASM = @VPX_X86_ASM@
 VPX_ARM_ASM = @VPX_ARM_ASM@
 VPX_NEED_OBJ_INT_EXTRACT = @VPX_NEED_OBJ_INT_EXTRACT@
 LIBJPEG_TURBO_AS = @LIBJPEG_TURBO_AS@
 LIBJPEG_TURBO_ASFLAGS = @LIBJPEG_TURBO_ASFLAGS@
 LIBJPEG_TURBO_X86_ASM = @LIBJPEG_TURBO_X86_ASM@
 LIBJPEG_TURBO_X64_ASM = @LIBJPEG_TURBO_X64_ASM@
+LIBJPEG_TURBO_ARM_ASM = @LIBJPEG_TURBO_ARM_ASM@
 NS_PRINTING = @NS_PRINTING@
 MOZ_PDF_PRINTING = @MOZ_PDF_PRINTING@
 MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
 MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
 MOC = @MOC@
 RCC = @RCC@
 MOZ_NSS_PATCH = @MOZ_NSS_PATCH@
 MOZ_WEBGL = @MOZ_WEBGL@
@@ -288,17 +288,16 @@ MOZ_ENABLE_GNOME_COMPONENT = @MOZ_ENABLE
 MOZ_ENABLE_GIO = @MOZ_ENABLE_GIO@
 MOZ_GIO_CFLAGS = @MOZ_GIO_CFLAGS@
 MOZ_GIO_LIBS = @MOZ_GIO_LIBS@
 
 MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@
 MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@
 
 MOZ_B2G_RIL = @MOZ_B2G_RIL@
-MOZ_B2G_BT = @MOZ_B2G_BT@
 
 BUILD_CTYPES = @BUILD_CTYPES@
 
 COMPILE_ENVIRONMENT = @COMPILE_ENVIRONMENT@
 CROSS_COMPILE   = @CROSS_COMPILE@
 
 WCHAR_CFLAGS	= @WCHAR_CFLAGS@
 
--- a/config/optimizejars.py
+++ b/config/optimizejars.py
@@ -30,17 +30,17 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-import sys, os, subprocess, struct
+import sys, os, subprocess, struct, re
 
 local_file_header = [
     ("signature", "uint32"),
     ("min_version", "uint16"),
     ("general_flag", "uint16"),
     ("compression", "uint16"),
     ("lastmod_time", "uint16"),
     ("lastmod_date", "uint16"),
@@ -324,35 +324,37 @@ def optimizejar(jar, outjar, inlog = Non
                               reordered_count, len(central_directory), outjar)
     outfd.close()
     return outlog
         
 if len(sys.argv) != 5:
     print "Usage: --optimize|--deoptimize %s JAR_LOG_DIR IN_JAR_DIR OUT_JAR_DIR" % sys.argv[0]
     exit(1)
 
+jar_regex = re.compile("\\.jar?$")
+
 def optimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR):
     ls = os.listdir(IN_JAR_DIR)
     for jarfile in ls:
-        if not jarfile.endswith(".jar"):
+        if not re.search(jar_regex, jarfile):
             continue
         injarfile = os.path.join(IN_JAR_DIR, jarfile)
         outjarfile = os.path.join(OUT_JAR_DIR, jarfile) 
         logfile = os.path.join(JAR_LOG_DIR, jarfile + ".log")
         if not os.path.isfile(logfile):
             logfile = None
         optimizejar(injarfile, outjarfile, logfile)
 
 def deoptimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR):
     if not os.path.exists(JAR_LOG_DIR):
         os.makedirs(JAR_LOG_DIR)
 
     ls = os.listdir(IN_JAR_DIR)
     for jarfile in ls:
-        if not jarfile.endswith(".jar"):
+        if not re.search(jar_regex, jarfile):
             continue
         injarfile = os.path.join(IN_JAR_DIR, jarfile)
         outjarfile = os.path.join(OUT_JAR_DIR, jarfile) 
         logfile = os.path.join(JAR_LOG_DIR, jarfile + ".log")
         log = optimizejar(injarfile, outjarfile, None)
         open(logfile, "wb").write("\n".join(log))
 
 def main():        
--- a/configure.in
+++ b/configure.in
@@ -3338,16 +3338,17 @@ fi         # GNU_CC
 if test "$SOLARIS_SUNPRO_CC"; then
 VISIBILITY_FLAGS='-xldscope=hidden'
 fi         # Sun Studio on Solaris
 
 AC_SUBST(WRAP_SYSTEM_INCLUDES)
 AC_SUBST(VISIBILITY_FLAGS)
 
 MOZ_GCC_PR49911
+MOZ_COMPILER_OPTS
 
 dnl Check for __force_align_arg_pointer__ for SSE2 on gcc
 dnl ========================================================
 if test "$GNU_CC"; then
   CFLAGS_save="${CFLAGS}"
   CFLAGS="${CFLAGS} -Werror"
   AC_CACHE_CHECK(for __force_align_arg_pointer__ attribute,
                  ac_cv_force_align_arg_pointer,
@@ -4086,16 +4087,66 @@ if test "$ac_cv_thread_keyword" = yes -a
       :
       ;;
     *)
       AC_DEFINE(HAVE_THREAD_TLS_KEYWORD)
       ;;
   esac
 fi
 
+dnl Using the custom linker on ARMv6 requires 16k alignment of ELF segments.
+if test -n "$MOZ_LINKER"; then
+  if test "$CPU_ARCH" = arm; then
+    dnl Determine the target ARM architecture (5 for ARMv5, v5T, v5E, etc.; 6 for ARMv6, v6K, etc.)
+    ARM_ARCH=`${CC-cc} ${CFLAGS} -dM -E - < /dev/null | sed -n 's/.*__ARM_ARCH_\([[0-9]]*\).*/\1/p'`
+    dnl When building for < ARMv7, we need to ensure 16k alignment of ELF segments
+    if test -n "$ARM_ARCH" && test "$ARM_ARCH" -lt 7; then
+      LDFLAGS="$LDFLAGS -Wl,-z,max-page-size=0x4000"
+      _SUBDIR_LDFLAGS="$_SUBDIR_LDFLAGS -Wl,-z,max-page-size=0x4000"
+    fi
+  fi
+fi
+
+dnl The custom linker doesn't support text relocations, but NDK >= r6b
+dnl creates some (http://code.google.com/p/android/issues/detail?id=23203)
+dnl We however want to avoid these text relocations, and this can be done
+dnl by making gcc not link crtbegin and crtend. In the broken NDKs, crtend
+dnl doesn't contain anything at all, beside placeholders for some sections,
+dnl and crtbegin only contains a finalizer function that calls
+dnl __cxa_finalize. The custom linker actually takes care of calling
+dnl __cxa_finalize when the library doesn't call it itself, which makes it
+dnl safe not to link crtbegin. Besides, previous versions of the NDK didn't
+dnl link crtbegin and crtend at all.
+if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$OS_TARGET" = "Android"; then
+  AC_CACHE_CHECK([whether the CRT objects have text relocations],
+    ac_cv_crt_has_text_relocations,
+    [echo 'int foo() { return 0; }' > conftest.cpp
+     if AC_TRY_COMMAND(${CXX-g++} -o conftest${DLL_SUFFIX} $CXXFLAGS $DSO_LDOPTS $LDFLAGS conftest.cpp $LIBS 1>&5) &&
+        test -s conftest${DLL_SUFFIX}; then
+       if readelf -d conftest${DLL_SUFFIX} | grep TEXTREL > /dev/null; then
+         ac_cv_crt_has_text_relocations=yes
+       else
+         ac_cv_crt_has_text_relocations=no
+       fi
+     else
+       AC_ERROR([couldn't compile a simple C file])
+     fi
+     rm -rf conftest*])
+  if test "$ac_cv_crt_has_text_relocations" = yes; then
+    dnl While we want libraries to skip the CRT files, we don't want
+    dnl executables to be treated the same way. We thus set the flag
+    dnl in DSO_LDOPTS and not LDFLAGS. However, to pass it to nspr,
+    dnl we need to use LDFLAGS because nspr doesn't inherit DSO_LDOPTS.
+    dnl Using LDFLAGS in nspr is safe, since we only really build
+    dnl libraries there.
+    DSO_LDOPTS="$DSO_LDOPTS -nostartfiles"
+    NSPR_LDFLAGS=-nostartfiles
+  fi
+fi
+
 dnl Check for the existence of various allocation headers/functions
 
 MALLOC_H=
 MOZ_CHECK_HEADER(malloc.h,        [MALLOC_H=malloc.h])
 if test "$MALLOC_H" = ""; then
   MOZ_CHECK_HEADER(malloc/malloc.h, [MALLOC_H=malloc/malloc.h])
   if test "$MALLOC_H" = ""; then
     MOZ_CHECK_HEADER(sys/malloc.h,    [MALLOC_H=sys/malloc.h])
@@ -4607,16 +4658,17 @@ VPX_AS_DASH_C_FLAG=
 VPX_AS_CONVERSION=
 VPX_ASM_SUFFIX=
 VPX_X86_ASM=
 VPX_ARM_ASM=
 LIBJPEG_TURBO_AS=
 LIBJPEG_TURBO_ASFLAGS=
 LIBJPEG_TURBO_X86_ASM=
 LIBJPEG_TURBO_X64_ASM=
+LIBJPEG_TURBO_ARM_ASM=
 MOZ_PANGO=1
 MOZ_PERMISSIONS=1
 MOZ_PLACES=1
 MOZ_PREF_EXTENSIONS=1
 MOZ_PROFILELOCKING=1
 MOZ_PSM=1
 MOZ_REFLOW_PERF=
 MOZ_SAFE_BROWSING=
@@ -4922,17 +4974,16 @@ cairo-gonk)
     AC_DEFINE(MOZ_TOUCH)
     MOZ_WIDGET_TOOLKIT=gonk
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
     MOZ_B2G_RIL=1
     MOZ_TOUCH=1
-    MOZ_B2G_BT=1
     ;;
 
 esac
 
 AC_SUBST(MOZ_OLD_LINKER)
 AC_SUBST(MOZ_PDF_PRINTING)
 if test "$MOZ_PDF_PRINTING"; then
    PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
@@ -6166,48 +6217,61 @@ if test -n "$MOZ_LIBJPEG_TURBO"; then
   WINNT:x86|WINNT:i?86)
     LIBJPEG_TURBO_ASFLAGS="-f win32 -rnasm -pnasm -DPIC -DWIN32"
     LIBJPEG_TURBO_X86_ASM=1
   ;;
   WINNT:x86_64)
     LIBJPEG_TURBO_ASFLAGS="-f win64 -rnasm -pnasm -D__x86_64__ -DPIC -DWIN64 -DMSVC"
     LIBJPEG_TURBO_X64_ASM=1
   ;;
+  *:arm*)
+    LIBJPEG_TURBO_ASFLAGS="-march=armv7-a -mfpu=neon"
+    LIBJPEG_TURBO_ARM_ASM=1
+  ;;
   esac
 
 fi
 
-dnl If we're on a system which supports libjpeg-turbo's asm routines and
-dnl --disable-libjpeg-turbo wasn't passed, check for yasm, and error out if it
-dnl doesn't exist or we have too old of a version.
+dnl If we're on an x86 or x64 system which supports libjpeg-turbo's asm routines
+dnl and --disable-libjpeg-turbo wasn't passed, check for Yasm, and error out if
+dnl it doesn't exist or we have too old of a version.
 if test -n "$LIBJPEG_TURBO_X86_ASM" -o -n "$LIBJPEG_TURBO_X64_ASM" ; then
-    AC_MSG_CHECKING([for YASM assembler])
+    AC_MSG_CHECKING([for Yasm assembler])
     AC_CHECK_PROGS(LIBJPEG_TURBO_AS, yasm, "")
 
     if test -z "$LIBJPEG_TURBO_AS" ; then
-        AC_MSG_ERROR([yasm is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you do not appear to have yasm installed.  Either install it or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder.  See https://developer.mozilla.org/en/YASM for more details.])
+        AC_MSG_ERROR([Yasm is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you do not appear to have Yasm installed.  Either install it or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder.  See https://developer.mozilla.org/en/YASM for more details.])
     fi
 
     dnl Check that we have the right yasm version.  We require 1.0.1 or newer
     dnl on Linux and 1.1 or newer everywhere else.
     if test "$OS_ARCH" = "Linux" ; then
         if test "$_YASM_MAJOR_VERSION" -lt "1" -o \( "$_YASM_MAJOR_VERSION" -eq "1" -a "$_YASM_MINOR_VERSION" -eq "0" -a "$_YASM_RELEASE" -lt "1" \) ; then
-            AC_MSG_ERROR([yasm 1.0.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION.$_YASM_RELEASE.  Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder.  See https://developer.mozilla.org/en/YASM for more details.])
+            AC_MSG_ERROR([Yasm 1.0.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION.$_YASM_RELEASE.  Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder.  See https://developer.mozilla.org/en/YASM for more details.])
         fi
     else
         if test "$_YASM_MAJOR_VERSION" -lt "1" -o \( "$_YASM_MAJOR_VERSION" -eq "1" -a "$_YASM_MINOR_VERSION" -lt "1" \) ; then
-            AC_MSG_ERROR([yasm 1.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION.  Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder.  See https://developer.mozilla.org/en/YASM for more details.])
+            AC_MSG_ERROR([Yasm 1.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION.  Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder.  See https://developer.mozilla.org/en/YASM for more details.])
         fi
     fi
 fi
 
+dnl If we're on an ARM system which supports libjpeg-turbo's asm routines and
+dnl --disable-libjpeg-turbo wasn't passed, use the C compiler as the assembler.
+if test -n "$LIBJPEG_TURBO_ARM_ASM" ; then
+    echo "Using $AS as the assembler for ARM code."
+    LIBJPEG_TURBO_AS=$AS
+fi
+
 if test -n "$LIBJPEG_TURBO_X86_ASM"; then
     AC_DEFINE(LIBJPEG_TURBO_X86_ASM)
 elif test -n "$LIBJPEG_TURBO_X64_ASM"; then
     AC_DEFINE(LIBJPEG_TURBO_X64_ASM)
+elif test -n "$LIBJPEG_TURBO_ARM_ASM"; then
+    AC_DEFINE(LIBJPEG_TURBO_ARM_ASM)
 elif test -n "$MOZ_LIBJPEG_TURBO"; then
     dnl Warn if we're not building the optimized routines, even though the user
     dnl didn't specify --disable-libjpeg-turbo.
     AC_MSG_WARN([No assembler or assembly support for libjpeg-turbo.  Using unoptimized C routines.])
 fi
 
 dnl ========================================================
 dnl = Enable compilation of specific extension modules
@@ -7594,28 +7658,16 @@ MOZ_ARG_ENABLE_BOOL(b2g-ril,
     MOZ_B2G_RIL=1,
     MOZ_B2G_RIL= )
 if test -n "$MOZ_B2G_RIL"; then
    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)
-fi
-AC_SUBST(MOZ_B2G_BT)
-
-dnl ========================================================
 dnl = Support for demangling undefined symbols
 dnl ========================================================
 if test -z "$SKIP_LIBRARY_CHECKS"; then
     AC_LANG_SAVE
     AC_LANG_CPLUSPLUS
     AC_CHECK_FUNCS(__cxa_demangle, HAVE_DEMANGLE=1, HAVE_DEMANGLE=)
     AC_LANG_RESTORE
 fi
@@ -8580,18 +8632,16 @@ AC_SUBST(MOZ_PROFILE_MIGRATOR)
 AC_SUBST(MOZ_EXTENSION_MANAGER)
 AC_DEFINE_UNQUOTED(MOZ_APP_UA_NAME, "$MOZ_APP_UA_NAME")
 AC_SUBST(MOZ_APP_UA_NAME)
 AC_DEFINE_UNQUOTED(MOZ_APP_UA_VERSION, "$MOZ_APP_VERSION")
 AC_SUBST(MOZ_APP_VERSION)
 AC_DEFINE_UNQUOTED(MOZ_UA_FIREFOX_VERSION, "$FIREFOX_VERSION")
 AC_DEFINE_UNQUOTED(FIREFOX_VERSION,$FIREFOX_VERSION)
 AC_SUBST(FIREFOX_VERSION)
-AC_DEFINE_UNQUOTED(MOZ_UA_BUILDID, "$MOZ_UA_BUILDID")
-AC_SUBST(MOZ_UA_BUILDID)
 
 # We can't use the static application.ini data when building against
 # a libxul SDK.
 if test -n "$LIBXUL_SDK"; then
     MOZ_APP_STATIC_INI=
 fi
 AC_SUBST(MOZ_APP_STATIC_INI)
 
@@ -8751,16 +8801,17 @@ AC_SUBST(VPX_ASM_SUFFIX)
 AC_SUBST(VPX_X86_ASM)
 AC_SUBST(VPX_ARM_ASM)
 AC_SUBST(VPX_NEED_OBJ_INT_EXTRACT)
 AC_SUBST(MOZ_INSTRUMENT_EVENT_LOOP)
 AC_SUBST(LIBJPEG_TURBO_AS)
 AC_SUBST(LIBJPEG_TURBO_ASFLAGS)
 AC_SUBST(LIBJPEG_TURBO_X86_ASM)
 AC_SUBST(LIBJPEG_TURBO_X64_ASM)
+AC_SUBST(LIBJPEG_TURBO_ARM_ASM)
 
 AC_MSG_CHECKING([for posix_fallocate])
 AC_TRY_LINK([#define _XOPEN_SOURCE 600
   #include <fcntl.h>],
                  [posix_fallocate(0, 0, 0);],
                  [ac_cv___posix_fallocate=true],
                  [ac_cv___posix_fallocate=false])
 
@@ -9085,17 +9136,21 @@ if test -z "$MOZ_NATIVE_NSPR"; then
         ac_configure_args="$ac_configure_args --with-arm-kuser"
     fi
     if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$ac_cv_func_dladdr" = no ; then
       # dladdr is supported by the new linker, even when the system linker doesn't
       # support it. Trick nspr into using dladdr when it's not supported.
       _SAVE_CPPFLAGS="$CPPFLAGS"
       export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
     fi
+    _SAVE_LDFLAGS="$LDFLAGS"
+    export LDFLAGS="$LDFLAGS $NSPR_LDFLAGS"
     AC_OUTPUT_SUBDIRS(nsprpub)
+    unset LDFLAGS
+    LDFLAGS="$_SAVE_LDFLAGS"
     if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$ac_cv_func_dladdr" = no; then
       unset CPPFLAGS
       CPPFLAGS="$_SAVE_CFLAGS"
     fi
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
--- a/content/base/crashtests/700512-worker.js
+++ b/content/base/crashtests/700512-worker.js
@@ -1,7 +1,7 @@
 onmessage = function(event) {
   var blob = event.data;
 
-  blob.mozSlice(1, 5);
+  blob.slice(1, 5);
 
   postMessage("done");
 }
--- a/content/base/public/nsIDOMFile.idl
+++ b/content/base/public/nsIDOMFile.idl
@@ -66,19 +66,19 @@ interface nsIDOMBlob : nsISupports
   readonly attribute unsigned long long size;
   readonly attribute DOMString type;
 
   [noscript] readonly attribute nsIInputStream internalStream;
   // The caller is responsible for releasing the internalUrl from the
   // blob: protocol handler
   [noscript] DOMString getInternalUrl(in nsIPrincipal principal);
 
-  [optional_argc] nsIDOMBlob mozSlice([optional] in long long start,
-                                      [optional] in long long end,
-                                      [optional] in DOMString contentType);
+  [optional_argc] nsIDOMBlob slice([optional] in long long start,
+                                   [optional] in long long end,
+                                   [optional] in DOMString contentType);
 
   // Get internal id of stored file. Returns -1 if it is not a stored file.
   // Intended only for testing. It can be called on any thread.
   [notxpcom] long long getFileId();
 
   // Called when the blob was successfully stored in a database or when
   // the blob is initialized from a database. It can be called on any thread.
   [notxpcom] void addFileInfo(in FileInfo aFileInfo);
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -43,16 +43,17 @@
 
 // Helper Classes
 #include "nsString.h"
 
 // Interfaces needed to be included
 #include "nsCopySupport.h"
 #include "nsIDOMUIEvent.h"
 #include "nsISelection.h"
+#include "nsISelectionController.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMDragEvent.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
@@ -65,71 +66,41 @@
 #include "nsISupportsPrimitives.h"
 #include "nsServiceManagerUtils.h"
 #include "nsNetUtil.h"
 #include "nsIFile.h"
 #include "nsIWebNavigation.h"
 #include "nsIDocShell.h"
 #include "nsIContent.h"
 #include "nsIImageLoadingContent.h"
+#include "nsITextControlElement.h"
 #include "nsUnicharUtils.h"
 #include "nsIURL.h"
 #include "nsIDocument.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIWebBrowserPersist.h"
 #include "nsEscape.h"
 #include "nsContentUtils.h"
 #include "nsIMIMEService.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsDOMDataTransfer.h"
 
-// private clipboard data flavors for html copy, used by editor when pasting
-#define kHTMLContext   "text/_moz_htmlcontext"
-#define kHTMLInfo      "text/_moz_htmlinfo"
-
-// if aNode is null, use the selection from the window
-static nsresult
-GetTransferableForNodeOrSelection(nsIDOMWindow*     aWindow,
-                                  nsIContent*       aNode,
-                                  nsITransferable** aTransferable)
-{
-  NS_ENSURE_ARG_POINTER(aWindow);
-
-  nsCOMPtr<nsIDOMDocument> domDoc;
-  aWindow->GetDocument(getter_AddRefs(domDoc));
-  NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
-
-  nsresult rv;
-  if (aNode) {
-    rv = nsCopySupport::GetTransferableForNode(aNode, doc, aTransferable);
-  } else {
-    nsCOMPtr<nsISelection> selection;
-    aWindow->GetSelection(getter_AddRefs(selection));
-    rv = nsCopySupport::GetTransferableForSelection(selection, doc,
-                                                    aTransferable);
-  }
-
-  NS_ENSURE_SUCCESS(rv, rv);
-  return rv;
-}
-
 class NS_STACK_CLASS DragDataProducer
 {
 public:
   DragDataProducer(nsIDOMWindow* aWindow,
                    nsIContent* aTarget,
                    nsIContent* aSelectionTargetNode,
                    bool aIsAltKeyPressed);
   nsresult Produce(nsDOMDataTransfer* aDataTransfer,
                    bool* aCanDrag,
-                   bool* aDragSelection,
+                   nsISelection** aSelection,
                    nsIContent** aDragNode);
 
 private:
   void AddString(nsDOMDataTransfer* aDataTransfer,
                  const nsAString& aFlavor,
                  const nsAString& aData,
                  nsIPrincipal* aPrincipal);
   nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
@@ -167,26 +138,26 @@ private:
 
 nsresult
 nsContentAreaDragDrop::GetDragData(nsIDOMWindow* aWindow,
                                    nsIContent* aTarget,
                                    nsIContent* aSelectionTargetNode,
                                    bool aIsAltKeyPressed,
                                    nsDOMDataTransfer* aDataTransfer,
                                    bool* aCanDrag,
-                                   bool* aDragSelection,
+                                   nsISelection** aSelection,
                                    nsIContent** aDragNode)
 {
   NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG);
 
   *aCanDrag = true;
 
   DragDataProducer
     provider(aWindow, aTarget, aSelectionTargetNode, aIsAltKeyPressed);
-  return provider.Produce(aDataTransfer, aCanDrag, aDragSelection, aDragNode);
+  return provider.Produce(aDataTransfer, aCanDrag, aSelection, aDragNode);
 }
 
 
 NS_IMPL_ISUPPORTS1(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider)
 
 // SaveURIToFile
 // used on platforms where it's possible to drag items (e.g. images)
 // into the file system
@@ -407,55 +378,94 @@ DragDataProducer::GetNodeString(nsIConte
       range->ToString(outNodeString);
     }
   }
 }
 
 nsresult
 DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
                           bool* aCanDrag,
-                          bool* aDragSelection,
+                          nsISelection** aSelection,
                           nsIContent** aDragNode)
 {
-  NS_PRECONDITION(aCanDrag && aDragSelection && aDataTransfer && aDragNode,
+  NS_PRECONDITION(aCanDrag && aSelection && aDataTransfer && aDragNode,
                   "null pointer passed to Produce");
   NS_ASSERTION(mWindow, "window not set");
   NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set");
 
   *aDragNode = nsnull;
 
   nsresult rv;
   nsIContent* dragNode = nsnull;
-
-  // find the selection to see what we could be dragging and if
-  // what we're dragging is in what is selected.
-  nsCOMPtr<nsISelection> selection;
-  mWindow->GetSelection(getter_AddRefs(selection));
-  if (!selection) {
-    return NS_OK;
-  }
+  *aSelection = nsnull;
 
-  // check if the node is inside a form control. If so, dragging will be
-  // handled in editor code (nsPlaintextDataTransfer::DoDrag). Don't set
-  // aCanDrag to false however, as we still want to allow the drag.
-  nsCOMPtr<nsIContent> findFormNode = mSelectionTargetNode;
-  nsIContent* findFormParent = findFormNode->GetParent();
-  while (findFormParent) {
-    nsCOMPtr<nsIFormControl> form(do_QueryInterface(findFormParent));
-    if (form && !form->AllowDraggableChildren()) {
+  // Find the selection to see what we could be dragging and if what we're
+  // dragging is in what is selected. If this is an editable textbox, use
+  // the textbox's selection, otherwise use the window's selection.
+  nsCOMPtr<nsISelection> selection;
+  nsIContent* editingElement = mSelectionTargetNode->IsEditable() ?
+                               mSelectionTargetNode->GetEditingHost() : nsnull;
+  nsCOMPtr<nsITextControlElement> textControl(do_QueryInterface(editingElement));
+  if (textControl) {
+    nsISelectionController* selcon = textControl->GetSelectionController();
+    if (selcon) {
+      selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
+      if (!selection)
+        return NS_OK;
+    }
+  }
+  else {
+    mWindow->GetSelection(getter_AddRefs(selection));
+    if (!selection)
       return NS_OK;
+
+    // Check if the node is inside a form control. Don't set aCanDrag to false
+    //however, as we still want to allow the drag.
+    nsCOMPtr<nsIContent> findFormNode = mSelectionTargetNode;
+    nsIContent* findFormParent = findFormNode->GetParent();
+    while (findFormParent) {
+      nsCOMPtr<nsIFormControl> form(do_QueryInterface(findFormParent));
+      if (form && !form->AllowDraggableChildren()) {
+        return NS_OK;
+      }
+      findFormParent = findFormParent->GetParent();
     }
-    findFormParent = findFormParent->GetParent();
   }
     
   // if set, serialize the content under this node
   nsCOMPtr<nsIContent> nodeToSerialize;
-  *aDragSelection = false;
+
+  bool isChromeShell = false;
+  nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(mWindow);
+  nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
+  if (dsti) {
+    PRInt32 type = -1;
+    if (NS_SUCCEEDED(dsti->GetItemType(&type)) &&
+        type == nsIDocShellTreeItem::typeChrome) {
+      isChromeShell = true;
+    }
+  }
 
-  {
+  // In chrome shells, only allow dragging inside editable areas.
+  if (isChromeShell && !editingElement)
+    return NS_OK;
+
+  if (isChromeShell && textControl) {
+    // Only use the selection if it isn't collapsed.
+    bool isCollapsed = false;
+    selection->GetIsCollapsed(&isCollapsed);
+    if (!isCollapsed)
+      selection.swap(*aSelection);
+  }
+  else {
+    // In content shells, a number of checks are made below to determine
+    // whether an image or a link is being dragged. If so, add additional
+    // data to the data transfer. This is also done for chrome shells, but
+    // only when in a non-textbox editor.
+
     bool haveSelectedContent = false;
 
     // possible parent link node
     nsCOMPtr<nsIContent> parentLink;
     nsCOMPtr<nsIContent> draggedNode;
 
     {
       // only drag form elements by using the alt key,
@@ -485,17 +495,17 @@ DragDataProducer::Produce(nsDOMDataTrans
     if (haveSelectedContent) {
       link = do_QueryInterface(selectedImageOrLinkNode);
       if (link && mIsAltKeyPressed) {
         // if alt is pressed, select the link text instead of drag the link
         *aCanDrag = false;
         return NS_OK;
       }
 
-      *aDragSelection = true;
+      selection.swap(*aSelection);
     } else if (selectedImageOrLinkNode) {
       // an image is selected
       image = do_QueryInterface(selectedImageOrLinkNode);
     } else {
       // nothing is selected -
       //
       // look for draggable elements under the mouse
       //
@@ -655,30 +665,38 @@ DragDataProducer::Produce(nsDOMDataTrans
       if (linkNode) {
         mIsAnchor = true;
         GetAnchorURL(linkNode, mUrlString);
         dragNode = linkNode;
       }
     }
   }
 
-  if (nodeToSerialize || *aDragSelection) {
-    // if we have selected text, use it in preference to the node
-    if (*aDragSelection) {
-      nodeToSerialize = nsnull;
-    }
-
+  if (nodeToSerialize || *aSelection) {
     mHtmlString.Truncate();
     mContextString.Truncate();
     mInfoString.Truncate();
     mTitleString.Truncate();
+
+    nsCOMPtr<nsIDOMDocument> domDoc;
+    mWindow->GetDocument(getter_AddRefs(domDoc));
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+    NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+
+    // if we have selected text, use it in preference to the node
     nsCOMPtr<nsITransferable> transferable;
-    rv = ::GetTransferableForNodeOrSelection(mWindow, nodeToSerialize,
-                                             getter_AddRefs(transferable));
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (*aSelection) {
+      rv = nsCopySupport::GetTransferableForSelection(*aSelection, doc,
+                                                      getter_AddRefs(transferable));
+    }
+    else {
+      rv = nsCopySupport::GetTransferableForNode(nodeToSerialize, doc,
+                                                 getter_AddRefs(transferable));
+    }
+
     nsCOMPtr<nsISupportsString> data;
     PRUint32 dataSize;
     rv = transferable->GetTransferData(kHTMLMime, getter_AddRefs(data), &dataSize);
     if (NS_SUCCEEDED(rv)) {
       data->GetData(mHtmlString);
     }
     rv = transferable->GetTransferData(kHTMLContext, getter_AddRefs(data), &dataSize);
     if (NS_SUCCEEDED(rv)) {
@@ -742,25 +760,27 @@ DragDataProducer::AddStringsToDataTransf
     dragData += mTitleString;
 
     AddString(aDataTransfer, NS_LITERAL_STRING(kURLMime), dragData, principal);
     AddString(aDataTransfer, NS_LITERAL_STRING(kURLDataMime), mUrlString, principal);
     AddString(aDataTransfer, NS_LITERAL_STRING(kURLDescriptionMime), mTitleString, principal);
     AddString(aDataTransfer, NS_LITERAL_STRING("text/uri-list"), mUrlString, principal);
   }
 
-  // add a special flavor, even if we don't have html context data
-  AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), mContextString, principal);
+  // add a special flavor for the html context data
+  if (!mContextString.IsEmpty())
+    AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), mContextString, principal);
 
   // add a special flavor if we have html info data
   if (!mInfoString.IsEmpty())
     AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), mInfoString, principal);
 
   // add the full html
-  AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLMime), mHtmlString, principal);
+  if (!mHtmlString.IsEmpty())
+    AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLMime), mHtmlString, principal);
 
   // add the plain text. we use the url for text/plain data if an anchor is
   // being dragged, rather than the title text of the link or the alt text for
   // an anchor image.
   AddString(aDataTransfer, NS_LITERAL_STRING(kTextMime),
             mIsAnchor ? mUrlString : mTitleString, principal);
 
   // add image data, if present. For now, all we're going to do with
--- a/content/base/src/nsContentAreaDragDrop.h
+++ b/content/base/src/nsContentAreaDragDrop.h
@@ -73,28 +73,28 @@ public:
    * aSelectionTargetNode - the node where the drag event should be fired
    * aIsAltKeyPressed - true if the Alt key is pressed. In some cases, this
    *                    will prevent the drag from occuring. For example,
    *                    holding down Alt over a link should select the text,
    *                    not drag the link.
    * aDataTransfer - the dataTransfer for the drag event.
    * aCanDrag - [out] set to true if the drag may proceed, false to stop the
    *            drag entirely
-   * aDragSelection - [out] set to true to indicate that a selection is being
-   *                  dragged, rather than a specific node
+   * aSelection - [out] set to the selection being dragged, or null if no
+   *                    selection is being dragged.
    * aDragNode - [out] the link, image or area being dragged, or null if the
    *             drag occurred on another element.
    */
   static nsresult GetDragData(nsIDOMWindow* aWindow,
                               nsIContent* aTarget,
                               nsIContent* aSelectionTargetNode,
                               bool aIsAltKeyPressed,
                               nsDOMDataTransfer* aDataTransfer,
                               bool* aCanDrag,
-                              bool* aDragSelection,
+                              nsISelection** aSelection,
                               nsIContent** aDragNode);
 };
 
 // this is used to save images to disk lazily when the image data is asked for
 // during the drop instead of when it is added to the drag data transfer. This
 // ensures that the image data is only created when an image drop is allowed.
 class nsContentAreaDragDropDataProvider : public nsIFlavorDataProvider
 {
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -86,20 +86,16 @@
 using namespace mozilla;
 
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
 
 static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
 static NS_DEFINE_CID(kCTransferableCID,        NS_TRANSFERABLE_CID);
 static NS_DEFINE_CID(kHTMLConverterCID,        NS_HTMLFORMATCONVERTER_CID);
 
-// private clipboard data flavors for html copy, used by editor when pasting
-#define kHTMLContext   "text/_moz_htmlcontext"
-#define kHTMLInfo      "text/_moz_htmlinfo"
-
 // copy string data onto the transferable
 static nsresult AppendString(nsITransferable *aTransferable,
                              const nsAString& aString,
                              const char* aFlavor);
 
 // copy HTML node data
 static nsresult AppendDOMNode(nsITransferable *aTransferable,
                               nsIDOMNode *aDOMNode);
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -117,19 +117,19 @@ nsDOMMultipartFile::CreateSlice(PRUint64
     PRUint64 l;
     nsresult rv = blob->GetSize(&l);
     NS_ENSURE_SUCCESS(rv, nsnull);
 
     if (skipStart < l) {
       PRUint64 upperBound = NS_MIN<PRUint64>(l - skipStart, length);
 
       nsCOMPtr<nsIDOMBlob> firstBlob;
-      rv = blob->MozSlice(skipStart, skipStart + upperBound,
-                          aContentType, 3,
-                          getter_AddRefs(firstBlob));
+      rv = blob->Slice(skipStart, skipStart + upperBound,
+                       aContentType, 3,
+                       getter_AddRefs(firstBlob));
       NS_ENSURE_SUCCESS(rv, nsnull);
 
       // Avoid wrapping a single blob inside an nsDOMMultipartFile
       if (length == upperBound) {
         return firstBlob.forget();
       }
 
       blobs.AppendElement(firstBlob);
@@ -145,18 +145,18 @@ nsDOMMultipartFile::CreateSlice(PRUint64
     nsIDOMBlob* blob = mBlobs[i].get();
 
     PRUint64 l;
     nsresult rv = blob->GetSize(&l);
     NS_ENSURE_SUCCESS(rv, nsnull);
 
     if (length < l) {
       nsCOMPtr<nsIDOMBlob> lastBlob;
-      rv = blob->MozSlice(0, length, aContentType, 3,
-                          getter_AddRefs(lastBlob));
+      rv = blob->Slice(0, length, aContentType, 3,
+                       getter_AddRefs(lastBlob));
       NS_ENSURE_SUCCESS(rv, nsnull);
 
       blobs.AppendElement(lastBlob);
     } else {
       blobs.AppendElement(blob);
     }
     length -= NS_MIN<PRUint64>(l, length);
   }
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -233,19 +233,19 @@ ParseSize(PRInt64 aSize, PRInt64& aStart
   }
   else {
     aStart = newStartOffset.value();
     aEnd = newEndOffset.value();
   }
 }
 
 NS_IMETHODIMP
-nsDOMFileBase::MozSlice(PRInt64 aStart, PRInt64 aEnd,
-                        const nsAString& aContentType, PRUint8 optional_argc,
-                        nsIDOMBlob **aBlob)
+nsDOMFileBase::Slice(PRInt64 aStart, PRInt64 aEnd,
+                     const nsAString& aContentType, PRUint8 optional_argc,
+                     nsIDOMBlob **aBlob)
 {
   *aBlob = nsnull;
 
   // Truncate aStart and aEnd so that we stay within this file.
   PRUint64 thisLength;
   nsresult rv = GetSize(&thisLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1695,30 +1695,64 @@ nsINode::SetExplicitBaseURI(nsIURI* aURI
     SetHasExplicitBaseURI();
     NS_ADDREF(aURI);
   }
   return rv;
 }
 
 //----------------------------------------------------------------------
 
+static JSObject*
+GetJSObjectChild(nsWrapperCache* aCache)
+{
+  if (aCache->PreservingWrapper()) {
+    return aCache->GetWrapperPreserveColor();
+  }
+  return aCache->GetExpandoObjectPreserveColor();
+}
+
+static bool
+NeedsScriptTraverse(nsWrapperCache* aCache)
+{
+  JSObject* o = GetJSObjectChild(aCache);
+  return o && xpc_IsGrayGCThing(o);
+}
+
+//----------------------------------------------------------------------
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
 
+// If nsChildContentList is changed so that any additional fields are
+// traversed by the cycle collector, then CAN_SKIP must be updated.
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsChildContentList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsChildContentList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsChildContentList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsChildContentList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
+// nsChildContentList only ever has a single child, its wrapper, so if
+// the wrapper is black, the list can't be part of a garbage cycle.
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList)
+  return !NeedsScriptTraverse(tmp);
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList)
+  return !NeedsScriptTraverse(tmp);
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+// CanSkipThis returns false to avoid problems with incomplete unlinking.
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 NS_INTERFACE_TABLE_HEAD(nsChildContentList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsChildContentList)
     NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsINodeList)
     NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsIDOMNodeList)
   NS_OFFSET_AND_INTERFACE_TABLE_END
   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList)
@@ -4400,32 +4434,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
     }
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericElement)
   nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-static JSObject*
-GetJSObjectChild(nsINode* aNode)
-{
-  if (aNode->PreservingWrapper()) {
-    return aNode->GetWrapperPreserveColor();
-  }
-  return aNode->GetExpandoObjectPreserveColor();
-}
-                                  
-static bool
-NeedsScriptTraverse(nsINode* aNode)
-{
-  JSObject* o = GetJSObjectChild(aNode);
-  return o && xpc_IsGrayGCThing(o);
-}
-
 void
 nsGenericElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
                                void* aData)
 {
   PRUint32* gen = static_cast<PRUint32*>(aData);
   xpc_MarkInCCGeneration(static_cast<nsISupports*>(aChild), *gen);
 }
 
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -97,17 +97,17 @@ class nsChildContentList : public nsINod
 public:
   nsChildContentList(nsINode* aNode)
     : mNode(aNode)
   {
     SetIsProxy();
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsChildContentList)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsChildContentList)
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
                                bool *triedToWrap);
 
   // nsIDOMNodeList interface
   NS_DECL_NSIDOMNODELIST
 
--- a/content/base/test/fileutils.js
+++ b/content/base/test/fileutils.js
@@ -196,34 +196,34 @@ function checkMPSubmission(sub, expected
 }
 
 function testSlice(file, size, type, contents, fileType) {
   is(file.type, type, fileType + " file is correct type");
   is(file.size, size, fileType + " file is correct size");
   ok(file instanceof File, fileType + " file is a File");
   ok(file instanceof Blob, fileType + " file is also a Blob");
   
-  var slice = file.mozSlice(0, size);
+  var slice = file.slice(0, size);
   ok(slice instanceof Blob, fileType + " fullsize slice is a Blob");
   ok(!(slice instanceof File), fileType + " fullsize slice is not a File");
   
-  slice = file.mozSlice(0, 1234);
+  slice = file.slice(0, 1234);
   ok(slice instanceof Blob, fileType + " sized slice is a Blob");
   ok(!(slice instanceof File), fileType + " sized slice is not a File");
   
-  slice = file.mozSlice(0, size, "foo/bar");
+  slice = file.slice(0, size, "foo/bar");
   is(slice.type, "foo/bar", fileType + " fullsize slice foo/bar type");
 
-  slice = file.mozSlice(0, 5432, "foo/bar");
+  slice = file.slice(0, 5432, "foo/bar");
   is(slice.type, "foo/bar", fileType + " sized slice foo/bar type");
   
-  is(slice.mozSlice(0, 10).type, "", fileType + " slice-slice type");
-  is(slice.mozSlice(0, 10).size, 10, fileType + " slice-slice size");
-  is(slice.mozSlice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type");
-  is(slice.mozSlice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
+  is(slice.slice(0, 10).type, "", fileType + " slice-slice type");
+  is(slice.slice(0, 10).size, 10, fileType + " slice-slice size");
+  is(slice.slice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type");
+  is(slice.slice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
 
   // Start, end, expected size
   var indexes = [[0, size, size],
                  [0, 1234, 1234],
                  [size-500, size, 500],
                  [size-500, size+500, 500],
                  [size+500, size+1500, 0],
                  [0, 0, 0],
@@ -242,38 +242,38 @@ function testSlice(file, size, type, con
                  [0, 33000, 33000],
                  [1000, 34000, 33000],
                 ];
   
   for (var i = 0; i < indexes.length; ++i) {
     var sliceContents;
     var testName;
     if (indexes[i][0] == undefined) {
-      slice = file.mozSlice();
+      slice = file.slice();
       sliceContents = contents.slice();
       testName = fileType + " slice()";
     }
     else if (indexes[i][1] == undefined) {
-      slice = file.mozSlice(indexes[i][0]);
+      slice = file.slice(indexes[i][0]);
       sliceContents = contents.slice(indexes[i][0]);
       testName = fileType + " slice(" + indexes[i][0] + ")";
     }
     else {
-      slice = file.mozSlice(indexes[i][0], indexes[i][1]);
+      slice = file.slice(indexes[i][0], indexes[i][1]);
       sliceContents = contents.slice(indexes[i][0], indexes[i][1]);
       testName = fileType + " slice(" + indexes[i][0] + ", " + indexes[i][1] + ")";
     }
     is(slice.type, "", testName + " type");
     is(slice.size, indexes[i][2], testName + " size");
     is(sliceContents.length, indexes[i][2], testName + " data size");
     testFile(slice, sliceContents, testName);
   }
 
   // Slice of slice
-  var slice = file.mozSlice(0, 40000);
-  testFile(slice.mozSlice(5000, 42000), contents.slice(5000, 40000), "file slice slice");
+  var slice = file.slice(0, 40000);
+  testFile(slice.slice(5000, 42000), contents.slice(5000, 40000), "file slice slice");
   
   // ...of slice of slice
-  slice = slice.mozSlice(5000, 42000).mozSlice(400, 700);
+  slice = slice.slice(5000, 42000).slice(400, 700);
   SpecialPowers.gc();
   testFile(slice, contents.slice(5400, 5700), "file slice slice slice");
 }
 
--- a/content/base/test/test_blobbuilder.html
+++ b/content/base/test/test_blobbuilder.html
@@ -146,17 +146,17 @@ function doTest(data) {
 
     blobs.forEach(doAppend);
     ok(true, "Test " + testCounter + " appended all successfully");
     let blob = bb.getBlob();
     ok(blob, "Test " + testCounter + " got blob");
     ok(blob instanceof Blob, "Test " + testCounter + " blob is a Blob");
     ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File");
 
-    let slice = blob.mozSlice(test.start, test.start + test.length);
+    let slice = blob.slice(test.start, test.start + test.length);
     ok(slice, "Test " + testCounter + " got slice");
     ok(slice instanceof Blob, "Test " + testCounter + " slice is a Blob");
     ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File");
     is(slice.size, test.contents.length,
        "Test " + testCounter + " slice is correct size");
 
     testFile(slice, test.contents, "Test " + testCounter);
   }
--- a/content/base/test/test_fileapi_slice.html
+++ b/content/base/test/test_fileapi_slice.html
@@ -99,39 +99,39 @@ function imageLoadHandler(event) {
 
   testHasRun();
 }
 
 // image in the middle
 var imgfile = createFileWithData(testBinaryData + fileData + testBinaryData);
 is(imgfile.size, size + testBinaryData.length * 2, "correct file size (middle)");
 var img = new Image;
-img.src = URL.createObjectURL(imgfile.mozSlice(testBinaryData.length, testBinaryData.length + size));
+img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
 img.onload = imageLoadHandler;
 expectedTestCount++;
 
 // image at start
 var imgfile = createFileWithData(fileData + testBinaryData);
 is(imgfile.size, size + testBinaryData.length, "correct file size (start)");
 var img = new Image;
-img.src = URL.createObjectURL(imgfile.mozSlice(0, size));
+img.src = URL.createObjectURL(imgfile.slice(0, size));
 img.onload = imageLoadHandler;
 expectedTestCount++;
 
 // image at end
 var imgfile = createFileWithData(testBinaryData + fileData);
 is(imgfile.size, size + testBinaryData.length, "correct file size (end)");
 var img = new Image;
-img.src = URL.createObjectURL(imgfile.mozSlice(testBinaryData.length, testBinaryData.length + size));
+img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
 img.onload = imageLoadHandler;
 expectedTestCount++;
 
 // image past end
 var imgfile = createFileWithData(testBinaryData + fileData);
 is(imgfile.size, size + testBinaryData.length, "correct file size (past end)");
 var img = new Image;
-img.src = URL.createObjectURL(imgfile.mozSlice(testBinaryData.length, testBinaryData.length + size + 1000));
+img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size + 1000));
 img.onload = imageLoadHandler;
 expectedTestCount++;
 
 </script>
 </pre>
 </body> </html>
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -1019,17 +1019,17 @@ struct WebGLVertexAttribData {
     }
 
     GLuint actualStride() const {
         if (stride) return stride;
         return size * componentSize();
     }
 };
 
-class WebGLBuffer
+class WebGLBuffer MOZ_FINAL
     : public nsIWebGLBuffer
     , public WebGLRefCountedObject<WebGLBuffer>
     , public WebGLContextBoundObject
 {
 public:
     WebGLBuffer(WebGLContext *context)
         : WebGLContextBoundObject(context)
         , mHasEverBeenBound(false)
@@ -1153,17 +1153,17 @@ protected:
     PRUint8 mCachedMaxUbyteElement;
     bool mHasCachedMaxUbyteElement;
     PRUint16 mCachedMaxUshortElement;
     bool mHasCachedMaxUshortElement;
 
     void* mData; // in the case of an Element Array Buffer, we keep a copy.
 };
 
-class WebGLTexture
+class WebGLTexture MOZ_FINAL
     : public nsIWebGLTexture
     , public WebGLRefCountedObject<WebGLTexture>
     , public WebGLContextBoundObject
 {
 public:
     WebGLTexture(WebGLContext *context)
         : WebGLContextBoundObject(context)
         , mHasEverBeenBound(false)
@@ -1603,17 +1603,17 @@ public:
             if (mFakeBlackStatus == DontKnowIfNeedFakeBlack)
                 mFakeBlackStatus = DoNotNeedFakeBlack;
         }
 
         return mFakeBlackStatus == DoNeedFakeBlack;
     }
 };
 
-class WebGLShader
+class WebGLShader MOZ_FINAL
     : public nsIWebGLShader
     , public WebGLRefCountedObject<WebGLShader>
     , public WebGLContextBoundObject
 {
 public:
     WebGLShader(WebGLContext *context, WebGLenum stype)
         : WebGLContextBoundObject(context)
         , mType(stype)
@@ -1668,17 +1668,17 @@ protected:
     WebGLuint mGLName;
     WebGLenum mType;
     nsString mSource;
     nsCString mTranslationLog;
     bool mNeedsTranslation;
     WebGLMonotonicHandle mMonotonicHandle;
 };
 
-class WebGLProgram
+class WebGLProgram MOZ_FINAL
     : public nsIWebGLProgram
     , public WebGLRefCountedObject<WebGLProgram>
     , public WebGLContextBoundObject
 {
 public:
     WebGLProgram(WebGLContext *context)
         : WebGLContextBoundObject(context)
         , mLinkStatus(false)
@@ -1790,17 +1790,17 @@ protected:
     GLint mUniformMaxNameLength;
     GLint mAttribMaxNameLength;
     GLint mUniformCount;
     GLint mAttribCount;
     std::vector<bool> mAttribsInUse;
     WebGLMonotonicHandle mMonotonicHandle;
 };
 
-class WebGLRenderbuffer
+class WebGLRenderbuffer MOZ_FINAL
     : public nsIWebGLRenderbuffer
     , public WebGLRefCountedObject<WebGLRenderbuffer>
     , public WebGLRectangleObject
     , public WebGLContextBoundObject
 {
 public:
     WebGLRenderbuffer(WebGLContext *context)
         : WebGLContextBoundObject(context)
@@ -1996,17 +1996,17 @@ public:
             }
         }
 
         NS_ABORT(); // should never get there
         return false;
     }
 };
 
-class WebGLFramebuffer
+class WebGLFramebuffer MOZ_FINAL
     : public nsIWebGLFramebuffer
     , public WebGLRefCountedObject<WebGLFramebuffer>
     , public WebGLContextBoundObject
 {
 public:
     WebGLFramebuffer(WebGLContext *context)
         : WebGLContextBoundObject(context)
         , mHasEverBeenBound(false)
@@ -2291,17 +2291,17 @@ public:
     WebGLFramebufferAttachment mColorAttachment,
                                mDepthAttachment,
                                mStencilAttachment,
                                mDepthStencilAttachment;
 
     WebGLMonotonicHandle mMonotonicHandle;
 };
 
-class WebGLUniformLocation
+class WebGLUniformLocation MOZ_FINAL
     : public nsIWebGLUniformLocation
     , public WebGLContextBoundObject
     , public WebGLRefCountedObject<WebGLUniformLocation>
 {
 public:
     WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location)
         : WebGLContextBoundObject(context)
         , mProgram(program)
@@ -2332,17 +2332,17 @@ protected:
     nsRefPtr<WebGLProgram> mProgram;
 
     PRUint32 mProgramGeneration;
     GLint mLocation;
     WebGLMonotonicHandle mMonotonicHandle;
     friend class WebGLProgram;
 };
 
-class WebGLActiveInfo
+class WebGLActiveInfo MOZ_FINAL
     : public nsIWebGLActiveInfo
 {
 public:
     WebGLActiveInfo(WebGLint size, WebGLenum type, const char *nameptr, PRUint32 namelength) :
         mSize(size),
         mType(type)
     {
         mName.AssignASCII(nameptr, namelength);
@@ -2351,17 +2351,17 @@ public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLACTIVEINFO
 protected:
     WebGLint mSize;
     WebGLenum mType;
     nsString mName;
 };
 
-class WebGLShaderPrecisionFormat
+class WebGLShaderPrecisionFormat MOZ_FINAL
     : public nsIWebGLShaderPrecisionFormat
 {
 public:
     WebGLShaderPrecisionFormat(WebGLint rangeMin, WebGLint rangeMax, WebGLint precision) :
         mRangeMin(rangeMin),
         mRangeMax(rangeMax),
         mPrecision(precision)
     {
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -4372,17 +4372,17 @@ WebGLContext::CompileShader(nsIWebGLShad
 
         // notice that on Android, we always use SH_GLSL_OUTPUT, we never use the ESSL backend.
         // see bug 709947, the reason is that 1) we dont really need a ESSL backend since the
         // source is already ESSL, and 2) we ran into massive Android crashes when we used the ESSL backend.
         // But if we wanted to use shader transformations on ES platforms, we would have to use the
         // ESSL backend
         compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
                                        SH_WEBGL_SPEC,
-#ifdef MOZ_WIDGET_ANDROID
+#ifdef ANDROID
                                        SH_GLSL_OUTPUT,
 #else
                                        gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT,
 #endif
                                        &resources);
 
         // We're storing an actual instance of StripComments because, if we don't, the 
         // cleanSource nsAString instance will be destroyed before the reference is
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -175,17 +175,17 @@ CopyContext(gfxContext* dest, gfxContext
     }
 }
 
 /**
  ** nsCanvasGradient
  **/
 #define NS_CANVASGRADIENT_PRIVATE_IID \
     { 0x491d39d8, 0x4058, 0x42bd, { 0xac, 0x76, 0x70, 0xd5, 0x62, 0x7f, 0x02, 0x10 } }
-class nsCanvasGradient : public nsIDOMCanvasGradient
+class nsCanvasGradient MOZ_FINAL : public nsIDOMCanvasGradient
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
 
     nsCanvasGradient(gfxPattern* pat)
         : mPattern(pat)
     {
     }
@@ -233,17 +233,17 @@ NS_INTERFACE_MAP_BEGIN(nsCanvasGradient)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 /**
  ** nsCanvasPattern
  **/
 #define NS_CANVASPATTERN_PRIVATE_IID \
     { 0xb85c6c8a, 0x0624, 0x4530, { 0xb8, 0xee, 0xff, 0xdf, 0x42, 0xe8, 0x21, 0x6d } }
-class nsCanvasPattern : public nsIDOMCanvasPattern
+class nsCanvasPattern MOZ_FINAL : public nsIDOMCanvasPattern
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERN_PRIVATE_IID)
 
     nsCanvasPattern(gfxPattern* pat,
                     nsIPrincipal* principalForSecurityCheck,
                     bool forceWriteOnly,
                     bool CORSUsed)
--- a/content/canvas/test/webgl/failing_tests_mac.txt
+++ b/content/canvas/test/webgl/failing_tests_mac.txt
@@ -2,8 +2,10 @@ conformance/context/premultiplyalpha-tes
 conformance/glsl/misc/glsl-function-nodes.html
 conformance/glsl/misc/glsl-long-variable-names.html
 conformance/glsl/misc/shader-with-256-character-identifier.frag.html
 conformance/glsl/misc/shader-with-long-line.html
 conformance/more/conformance/quickCheckAPI-S_V.html
 conformance/glsl/misc/attrib-location-length-limits.html
 conformance/glsl/misc/uniform-location-length-limits.html
 conformance/programs/program-test.html
+conformance/textures/texture-mips.html
+conformance/textures/texture-npot.html
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -175,18 +175,17 @@ nsDOMEvent::nsDOMEvent(nsPresContext* aP
 
 void
 nsDOMEvent::InitPresContextData(nsPresContext* aPresContext)
 {
   mPresContext = aPresContext;
   // Get the explicit original target (if it's anonymous make it null)
   {
     nsCOMPtr<nsIContent> content = GetTargetFromFrame();
-    mTmpRealOriginalTarget = do_QueryInterface(content);
-    mExplicitOriginalTarget = mTmpRealOriginalTarget;
+    mExplicitOriginalTarget = do_QueryInterface(content);
     if (content && content->IsInAnonymousSubtree()) {
       mExplicitOriginalTarget = nsnull;
     }
   }
 }
 
 nsDOMEvent::~nsDOMEvent() 
 {
@@ -232,20 +231,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
       case NS_MUTATION_EVENT:
         static_cast<nsMutationEvent*>(tmp->mEvent)->mRelatedNode = nsnull;
         break;
       default:
         break;
     }
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPresContext);
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTmpRealOriginalTarget)
-  // Always set mExplicitOriginalTarget to null, when 
-  // mTmpRealOriginalTarget doesn't point to any object!
-  tmp->mExplicitOriginalTarget = nsnull;
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mExplicitOriginalTarget);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent)
   if (tmp->mEventIsInternal) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEvent->target)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEvent->currentTarget)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEvent->originalTarget)
     switch (tmp->mEvent->eventStructType) {
@@ -270,17 +266,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
         cb.NoteXPCOMChild(
           static_cast<nsMutationEvent*>(tmp->mEvent)->mRelatedNode);
         break;
       default:
         break;
     }
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPresContext.get(), nsPresContext)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTmpRealOriginalTarget)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mExplicitOriginalTarget)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // nsIDOMEventInterface
 NS_METHOD nsDOMEvent::GetType(nsAString& aType)
 {
   if (!mCachedType.IsEmpty()) {
     aType = mCachedType;
     return NS_OK;
@@ -351,28 +347,16 @@ nsDOMEvent::GetExplicitOriginalTarget(ns
     NS_ADDREF(*aRealEventTarget);
     return NS_OK;
   }
 
   return GetTarget(aRealEventTarget);
 }
 
 NS_IMETHODIMP
-nsDOMEvent::GetTmpRealOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
-{
-  if (mTmpRealOriginalTarget) {
-    *aRealEventTarget = mTmpRealOriginalTarget;
-    NS_ADDREF(*aRealEventTarget);
-    return NS_OK;
-  }
-
-  return GetOriginalTarget(aRealEventTarget);
-}
-
-NS_IMETHODIMP
 nsDOMEvent::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget)
 {
   if (mEvent->originalTarget) {
     return GetDOMEventTarget(mEvent->originalTarget, aOriginalTarget);
   }
 
   return GetTarget(aOriginalTarget);
 }
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -262,18 +262,17 @@ public:
 protected:
 
   // Internal helper functions
   nsresult SetEventType(const nsAString& aEventTypeArg);
   already_AddRefed<nsIContent> GetTargetFromFrame();
 
   nsEvent*                    mEvent;
   nsRefPtr<nsPresContext>     mPresContext;
-  nsCOMPtr<nsIDOMEventTarget> mTmpRealOriginalTarget;
-  nsIDOMEventTarget*          mExplicitOriginalTarget;
+  nsCOMPtr<nsIDOMEventTarget> mExplicitOriginalTarget;
   nsString                    mCachedType;
   bool                        mEventIsInternal;
   bool                        mPrivateDataDuplicated;
 };
 
 #define NS_FORWARD_TO_NSDOMEVENT \
   NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -2076,24 +2076,22 @@ nsEventStateManager::GenerateDragGesture
         // it takes a long time
         KillClickHoldTimer();
       }
 
       nsRefPtr<nsDOMDataTransfer> dataTransfer = new nsDOMDataTransfer();
       if (!dataTransfer)
         return;
 
-      bool isInEditor = false;
-      bool isSelection = false;
+      nsCOMPtr<nsISelection> selection;
       nsCOMPtr<nsIContent> eventContent, targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
       if (eventContent)
         DetermineDragTarget(aPresContext, eventContent, dataTransfer,
-                            &isSelection, &isInEditor,
-                            getter_AddRefs(targetContent));
+                            getter_AddRefs(selection), getter_AddRefs(targetContent));
 
       // Stop tracking the drag gesture now. This should stop us from
       // reentering GenerateDragGesture inside DOM event processing.
       StopTrackingDragGesture();
 
       if (!targetContent)
         return;
 
@@ -2124,36 +2122,35 @@ nsEventStateManager::GenerateDragGesture
 
       // Set the current target to the content for the mouse down
       mCurrentTargetContent = targetContent;
 
       // Dispatch both the dragstart and draggesture events to the DOM. For
       // elements in an editor, only fire the draggesture event so that the
       // editor code can handle it but content doesn't see a dragstart.
       nsEventStatus status = nsEventStatus_eIgnore;
-      if (!isInEditor)
-        nsEventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nsnull,
-                                    &status);
+      nsEventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nsnull,
+                                  &status);
 
       nsDragEvent* event = &startEvent;
       if (status != nsEventStatus_eConsumeNoDefault) {
         status = nsEventStatus_eIgnore;
         nsEventDispatcher::Dispatch(targetContent, aPresContext, &gestureEvent, nsnull,
                                     &status);
         event = &gestureEvent;
       }
 
       // now that the dataTransfer has been updated in the dragstart and
       // draggesture events, make it read only so that the data doesn't
       // change during the drag.
       dataTransfer->SetReadOnly();
 
       if (status != nsEventStatus_eConsumeNoDefault) {
         bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
-                                                targetContent, isSelection);
+                                              targetContent, selection);
         if (dragStarted) {
           sActiveESM = nsnull;
           aEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
         }
       }
 
       // Note that frame event handling doesn't care about NS_DRAGDROP_GESTURE,
       // which is just as well since we don't really know which frame to
@@ -2168,64 +2165,54 @@ nsEventStateManager::GenerateDragGesture
     FlushPendingEvents(aPresContext);
   }
 } // GenerateDragGesture
 
 void
 nsEventStateManager::DetermineDragTarget(nsPresContext* aPresContext,
                                          nsIContent* aSelectionTarget,
                                          nsDOMDataTransfer* aDataTransfer,
-                                         bool* aIsSelection,
-                                         bool* aIsInEditor,
+                                         nsISelection** aSelection,
                                          nsIContent** aTargetNode)
 {
   *aTargetNode = nsnull;
-  *aIsInEditor = false;
 
   nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
   nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container);
 
   // GetDragData determines if a selection, link or image in the content
   // should be dragged, and places the data associated with the drag in the
-  // data transfer. Skip this check for chrome shells.
+  // data transfer.
+  // mGestureDownContent is the node where the mousedown event for the drag
+  // occurred, and aSelectionTarget is the node to use when a selection is used
   bool canDrag;
   nsCOMPtr<nsIContent> dragDataNode;
-  nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(container);
-  if (dsti) {
-    PRInt32 type = -1;
-    if (NS_SUCCEEDED(dsti->GetItemType(&type)) &&
-        type != nsIDocShellTreeItem::typeChrome) {
-      // mGestureDownContent is the node where the mousedown event for the drag
-      // occurred, and aSelectionTarget is the node to use when a selection is used
-      nsresult rv =
-        nsContentAreaDragDrop::GetDragData(window, mGestureDownContent,
-                                           aSelectionTarget, mGestureDownAlt,
-                                           aDataTransfer, &canDrag, aIsSelection,
-                                           getter_AddRefs(dragDataNode));
-      if (NS_FAILED(rv) || !canDrag)
-        return;
-    }
-  }
+  nsresult rv = nsContentAreaDragDrop::GetDragData(window, mGestureDownContent,
+                                                   aSelectionTarget, mGestureDownAlt,
+                                                   aDataTransfer, &canDrag, aSelection,
+                                                   getter_AddRefs(dragDataNode));
+  if (NS_FAILED(rv) || !canDrag)
+    return;
 
   // if GetDragData returned a node, use that as the node being dragged.
   // Otherwise, if a selection is being dragged, use the node within the
   // selection that was dragged. Otherwise, just use the mousedown target.
   nsIContent* dragContent = mGestureDownContent;
   if (dragDataNode)
     dragContent = dragDataNode;
-  else if (*aIsSelection)
+  else if (*aSelection)
     dragContent = aSelectionTarget;
 
   nsIContent* originalDragContent = dragContent;
 
   // If a selection isn't being dragged, look for an ancestor with the
   // draggable property set. If one is found, use that as the target of the
   // drag instead of the node that was clicked on. If a draggable node wasn't
   // found, just use the clicked node.
-  if (!*aIsSelection) {
+  if (!*aSelection) {
     while (dragContent) {
       nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(dragContent);
       if (htmlElement) {
         bool draggable = false;
         htmlElement->GetDraggable(&draggable);
         if (draggable)
           break;
       }
@@ -2240,27 +2227,16 @@ nsEventStateManager::DetermineDragTarget
           // better way to specify whether something is draggable than just
           // on/off.
           dragContent = mGestureDownContent;
           break;
         }
         // otherwise, it's not an HTML or XUL element, so just keep looking
       }
       dragContent = dragContent->GetParent();
-
-      // if an editable parent is encountered, then we don't look at any
-      // ancestors. This is used because the editor attaches a draggesture
-      // listener to the editable element and we want to call it without
-      // making the editable element draggable. This should be removed once
-      // the editor is switched over to using the proper drag and drop api.
-      nsCOMPtr<nsIDOMNSEditableElement> editableElement = do_QueryInterface(dragContent);
-      if (editableElement) {
-        *aIsInEditor = true;
-        break;
-      }
     }
   }
 
   // if no node in the hierarchy was found to drag, but the GetDragData method
   // returned a node, use that returned node. Otherwise, nothing is draggable.
   if (!dragContent && dragDataNode)
     dragContent = dragDataNode;
 
@@ -2274,17 +2250,17 @@ nsEventStateManager::DetermineDragTarget
   }
 }
 
 bool
 nsEventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
                                         nsDragEvent* aDragEvent,
                                         nsDOMDataTransfer* aDataTransfer,
                                         nsIContent* aDragTarget,
-                                        bool aIsSelection)
+                                        nsISelection* aSelection)
 {
   nsCOMPtr<nsIDragService> dragService =
     do_GetService("@mozilla.org/widget/dragservice;1");
   if (!dragService)
     return false;
 
   // Default handling for the draggesture/dragstart event.
   //
@@ -2328,48 +2304,37 @@ nsEventStateManager::DoDefaultDragStart(
     action = nsIDragService::DRAGDROP_ACTION_COPY |
              nsIDragService::DRAGDROP_ACTION_MOVE |
              nsIDragService::DRAGDROP_ACTION_LINK;
 
   // get any custom drag image that was set
   PRInt32 imageX, imageY;
   nsIDOMElement* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
 
-  // If a selection is being dragged, and no custom drag image was
-  // set, get the selection so that the drag region can be created
-  // from the selection area. If a custom image was set, it doesn't
-  // matter what the selection is since the image will be used instead.
-  nsISelection* selection = nsnull;
-  if (aIsSelection && !dragImage) {
-    nsIDocument* doc = aDragTarget->GetCurrentDoc();
-    if (doc) {
-      nsIPresShell* presShell = doc->GetShell();
-      if (presShell) {
-        selection = presShell->GetCurrentSelection(
-                      nsISelectionController::SELECTION_NORMAL);
-      }
-    }
-  }
-
   nsCOMPtr<nsISupportsArray> transArray;
   aDataTransfer->GetTransferables(getter_AddRefs(transArray));
   if (!transArray)
     return false;
 
   // XXXndeakin don't really want to create a new drag DOM event
   // here, but we need something to pass to the InvokeDragSession
   // methods.
   nsCOMPtr<nsIDOMEvent> domEvent;
   NS_NewDOMDragEvent(getter_AddRefs(domEvent), aPresContext, aDragEvent);
 
   nsCOMPtr<nsIDOMDragEvent> domDragEvent = do_QueryInterface(domEvent);
   // if creating a drag event failed, starting a drag session will
   // just fail.
-  if (selection) {
-    dragService->InvokeDragSessionWithSelection(selection, transArray,
+
+  // Use InvokeDragSessionWithSelection if a selection is being dragged,
+  // such that the image can be generated from the selected text. However,
+  // use InvokeDragSessionWithImage if a custom image was set or something
+  // other than a selection is being dragged.
+  if (!dragImage && aSelection) {
+    dragService->InvokeDragSessionWithSelection(aSelection, transArray,
                                                 action, domDragEvent,
                                                 aDataTransfer);
   }
   else {
     // if dragging within a XUL tree and no custom drag image was
     // set, the region argument to InvokeDragSessionWithImage needs
     // to be set to the area encompassing the selected rows of the
     // tree to ensure that the drag feedback gets clipped to those
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -412,42 +412,40 @@ protected:
 
   /**
    * Determine which node the drag should be targeted at.
    * This is either the node clicked when there is a selection, or, for HTML,
    * the element with a draggable property set to true.
    *
    * aSelectionTarget - target to check for selection
    * aDataTransfer - data transfer object that will contain the data to drag
-   * aIsSelection - [out] set to true if a selection is being dragged
-   * aIsInEditor - [out] set to true if the content is in an editor field
+   * aSelection - [out] set to the selection to be dragged
    * aTargetNode - [out] the draggable node, or null if there isn't one
    */
   void DetermineDragTarget(nsPresContext* aPresContext,
                            nsIContent* aSelectionTarget,
                            nsDOMDataTransfer* aDataTransfer,
-                           bool* aIsSelection,
-                           bool* aIsInEditor,
+                           nsISelection** aSelection,
                            nsIContent** aTargetNode);
 
   /*
    * Perform the default handling for the dragstart/draggesture event and set up a
    * drag for aDataTransfer if it contains any data. Returns true if a drag has
    * started.
    *
    * aDragEvent - the dragstart/draggesture event
    * aDataTransfer - the data transfer that holds the data to be dragged
    * aDragTarget - the target of the drag
-   * aIsSelection - true if a selection is being dragged
+   * aSelection - the selection to be dragged
    */
   bool DoDefaultDragStart(nsPresContext* aPresContext,
                             nsDragEvent* aDragEvent,
                             nsDOMDataTransfer* aDataTransfer,
                             nsIContent* aDragTarget,
-                            bool aIsSelection);
+                            nsISelection* aSelection);
 
   bool IsTrackingDragGesture ( ) const { return mGestureDownContent != nsnull; }
   /**
    * Set the fields of aEvent to reflect the mouse position and modifier keys
    * that were set when the user first pressed the mouse button (stored by
    * BeginTrackingDragGesture). aEvent->widget must be
    * mCurrentTarget->GetNearestWidget().
    */
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -104,17 +104,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug448534.html \
 		test_bug463162.xhtml \
 		test_bug465498.html \
 		test_bug493187.html \
 		test_bug495145.html \
 		test_bug495300.html \
 		test_bug686942.html \
 		test_can_play_type.html \
-		test_closing_connections.html \
 		test_constants.html \
 		test_controls.html \
 		test_currentTime.html \
 		test_decode_error.html \
 		test_decoder_disable.html \
 		test_defaultMuted.html \
 		test_delay_load.html \
 		test_error_on_404.html \
@@ -171,16 +170,18 @@ endif
 # Bug 492821:
 #   test_videoDocumentTitle.html
 # Bug 493692:
 #   test_preload_suspend.html
 # Bug 567954 and Bug 574586:
 #   test_mixed_principals.html
 # Disabled since we don't play Wave files standalone, for now
 #		test_audioDocumentTitle.html
+# Bug 634564:
+#		test_closing_connections.html \
 
 # sample files
 _TEST_FILES += \
 		320x240.ogv \
 		448636.ogv \
 		audio-overhang.ogg \
 		audio-gaps.ogg \
 		beta-phrasebook.ogg \
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -1481,17 +1481,18 @@ nsSVGElement::GetCtx() const
     ancestor = ancestor->GetFlattenedTreeParent();
   }
 
   // we don't have an ancestor <svg> element...
   return nsnull;
 }
 
 /* virtual */ gfxMatrix
-nsSVGElement::PrependLocalTransformTo(const gfxMatrix &aMatrix) const
+nsSVGElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                                       TransformTypes aWhich) const
 {
   return aMatrix;
 }
 
 nsSVGElement::LengthAttributesInfo
 nsSVGElement::GetLengthInfo()
 {
   return LengthAttributesInfo(nsnull, nsnull, 0);
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -146,21 +146,46 @@ public:
   NS_IMETHOD GetOwnerSVGElement(nsIDOMSVGSVGElement** aOwnerSVGElement);
   NS_IMETHOD GetViewportElement(nsIDOMSVGElement** aViewportElement);
 
   // Gets the element that establishes the rectangular viewport against which
   // we should resolve percentage lengths (our "coordinate context"). Returns
   // nsnull for outer <svg> or SVG without an <svg> parent (invalid SVG).
   nsSVGSVGElement* GetCtx() const;
 
+  enum TransformTypes {
+     eAllTransforms
+    ,eUserSpaceToParent
+    ,eChildToUserSpace
+  };
   /**
-   * Returns aMatrix post-multiplied by the transform from the userspace
-   * established by this element to the userspace established by its parent.
+   * Returns aMatrix pre-multiplied by (explicit or implicit) transforms that
+   * are introduced by attributes on this element.
+   *
+   * If aWhich is eAllTransforms, then all the transforms from the coordinate
+   * space established by this element for its children to the coordinate
+   * space established by this element's parent element for this element, are
+   * included.
+   *
+   * If aWhich is eUserSpaceToParent, then only the transforms from this
+   * element's userspace to the coordinate space established by its parent is
+   * included. This includes any transforms introduced by the 'transform'
+   * attribute, transform animations and animateMotion, but not any offsets
+   * due to e.g. 'x'/'y' attributes, or any transform due to a 'viewBox'
+   * attribute. (SVG userspace is defined to be the coordinate space in which
+   * coordinates on an element apply.)
+   *
+   * If aWhich is eChildToUserSpace, then only the transforms from the
+   * coordinate space established by this element for its childre to this
+   * elements userspace are included. This includes any offsets due to e.g.
+   * 'x'/'y' attributes, and any transform due to a 'viewBox' attribute, but
+   * does not include any transforms due to the 'transform' attribute.
    */
-  virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix) const;
+  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                      TransformTypes aWhich = eAllTransforms) const;
 
   // Setter for to set the current <animateMotion> transformation
   // Only visible for nsSVGGraphicElement, so it's a no-op here, and that
   // subclass has the useful implementation.
   virtual void SetAnimateMotionTransform(const gfxMatrix* aMatrix) {/*no-op*/}
 
   bool IsStringAnimatable(PRUint8 aAttrEnum) {
     return GetStringInfo().mStringInfo[aAttrEnum].mIsAnimatable;
--- a/content/svg/content/src/nsSVGForeignObjectElement.cpp
+++ b/content/svg/content/src/nsSVGForeignObjectElement.cpp
@@ -107,26 +107,38 @@ NS_IMETHODIMP nsSVGForeignObjectElement:
 {
   return mLengthAttributes[HEIGHT].ToDOMAnimatedLength(aHeight, this);
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
-nsSVGForeignObjectElement::PrependLocalTransformTo(const gfxMatrix &aMatrix) const
+nsSVGForeignObjectElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                                                    TransformTypes aWhich) const
 {
+  NS_ABORT_IF_FALSE(aWhich != eChildToUserSpace || aMatrix.IsIdentity(),
+                    "Skipping eUserSpaceToParent transforms makes no sense");
+
   // 'transform' attribute:
-  gfxMatrix matrix = nsSVGForeignObjectElementBase::PrependLocalTransformTo(aMatrix);
-  
-  // now translate by our 'x' and 'y':
+  gfxMatrix fromUserSpace =
+    nsSVGForeignObjectElementBase::PrependLocalTransformsTo(aMatrix, aWhich);
+  if (aWhich == eUserSpaceToParent) {
+    return fromUserSpace;
+  }
+  // our 'x' and 'y' attributes:
   float x, y;
   const_cast<nsSVGForeignObjectElement*>(this)->
     GetAnimatedLengthValues(&x, &y, nsnull);
-  return gfxMatrix().Translate(gfxPoint(x, y)) * matrix;
+  gfxMatrix toUserSpace = gfxMatrix().Translate(gfxPoint(x, y));
+  if (aWhich == eChildToUserSpace) {
+    return toUserSpace;
+  }
+  NS_ABORT_IF_FALSE(aWhich == eAllTransforms, "Unknown TransformTypes");
+  return toUserSpace * fromUserSpace;
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(bool)
 nsSVGForeignObjectElement::IsAttributeMapped(const nsIAtom* name) const
 {
--- a/content/svg/content/src/nsSVGForeignObjectElement.h
+++ b/content/svg/content/src/nsSVGForeignObjectElement.h
@@ -64,17 +64,18 @@ public:
   NS_DECL_NSIDOMSVGFOREIGNOBJECTELEMENT
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGForeignObjectElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGForeignObjectElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGForeignObjectElementBase::)
 
   // nsSVGElement specializations:
-  virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix) const;
+  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                      TransformTypes aWhich = eAllTransforms) const;
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
--- a/content/svg/content/src/nsSVGGraphicElement.cpp
+++ b/content/svg/content/src/nsSVGGraphicElement.cpp
@@ -184,20 +184,35 @@ nsSVGGraphicElement::IsAttributeMapped(c
 
 bool
 nsSVGGraphicElement::IsEventName(nsIAtom* aName)
 {
   return nsContentUtils::IsEventAttributeName(aName, EventNameType_SVGGraphic);
 }
 
 gfxMatrix
-nsSVGGraphicElement::PrependLocalTransformTo(const gfxMatrix &aMatrix) const
+nsSVGGraphicElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                                              TransformTypes aWhich) const
 {
+  NS_ABORT_IF_FALSE(aWhich != eChildToUserSpace || aMatrix.IsIdentity(),
+                    "Skipping eUserSpaceToParent transforms makes no sense");
+
   gfxMatrix result(aMatrix);
 
+  if (aWhich == eChildToUserSpace) {
+    // We don't have anything to prepend.
+    // eChildToUserSpace is not the common case, which is why we return
+    // 'result' to benefit from NRVO rather than returning aMatrix before
+    // creating 'result'.
+    return result;
+  }
+
+  NS_ABORT_IF_FALSE(aWhich == eAllTransforms || aWhich == eUserSpaceToParent,
+                    "Unknown TransformTypes");
+
   // animateMotion's resulting transform is supposed to apply *on top of*
   // any transformations from the |transform| attribute. So since we're
   // PRE-multiplying, we need to apply the animateMotion transform *first*.
   if (mAnimateMotionTransform) {
     result.PreMultiply(*mAnimateMotionTransform);
   }
 
   if (mTransforms) {
--- a/content/svg/content/src/nsSVGGraphicElement.h
+++ b/content/svg/content/src/nsSVGGraphicElement.h
@@ -57,17 +57,18 @@ public:
   // interfaces:  
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMSVGLOCATABLE
   NS_DECL_NSIDOMSVGTRANSFORMABLE
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
-  virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix) const;
+  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                      TransformTypes aWhich = eAllTransforms) const;
   virtual void SetAnimateMotionTransform(const gfxMatrix* aMatrix);
 
   virtual mozilla::SVGAnimatedTransformList* GetAnimatedTransformList();
   virtual nsIAtom* GetTransformListAttrName() const {
     return nsGkAtoms::transform;
   }
 
 protected:
--- a/content/svg/content/src/nsSVGPathElement.cpp
+++ b/content/svg/content/src/nsSVGPathElement.cpp
@@ -435,17 +435,17 @@ nsSVGPathElement::GetPathLengthScale(Pat
   if (mPathLength.IsExplicitlySet()) {
     float authorsPathLengthEstimate = mPathLength.GetAnimValue();
     if (authorsPathLengthEstimate > 0) {
       gfxMatrix matrix;
       if (aFor == eForTextPath) {
         // For textPath, a transform on the referenced path affects the
         // textPath layout, so when calculating the actual path length
         // we need to take that into account.
-        matrix = PrependLocalTransformTo(matrix);
+        matrix = PrependLocalTransformsTo(matrix);
       }
       nsRefPtr<gfxFlattenedPath> path = GetFlattenedPath(matrix);
       if (path) {
         return path->GetLength() / authorsPathLengthEstimate;
       }
     }
   }
   return 1.0;
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -745,17 +745,26 @@ nsSVGSVGElement::GetCTM(nsIDOMSVGMatrix 
   NS_IF_ADDREF(*aCTM);
   return NS_OK;
 }
 
 /* nsIDOMSVGMatrix getScreenCTM (); */
 NS_IMETHODIMP
 nsSVGSVGElement::GetScreenCTM(nsIDOMSVGMatrix **aCTM)
 {
-  gfxMatrix m = nsSVGUtils::GetCTM(this, true);
+  gfxMatrix m;
+  if (IsRoot()) {
+    // Consistency with other elements would have us return only the
+    // eFromUserSpace transforms, but this is what we've been doing for
+    // a while, and it keeps us consistent with WebKit and Opera (if not
+    // really with the ambiguous spec).
+    m = PrependLocalTransformsTo(m);
+  } else {
+    m = nsSVGUtils::GetCTM(this, true);
+  }
   *aCTM = m.IsSingular() ? nsnull : new DOMSVGMatrix(m);
   NS_IF_ADDREF(*aCTM);
   return NS_OK;
 }
 
 /* nsIDOMSVGMatrix getTransformToElement (in nsIDOMSVGElement element); */
 NS_IMETHODIMP
 nsSVGSVGElement::GetTransformToElement(nsIDOMSVGElement *element,
@@ -1175,22 +1184,39 @@ nsSVGSVGElement::GetLength(PRUint8 aCtxT
   }
   return 0;
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
-nsSVGSVGElement::PrependLocalTransformTo(const gfxMatrix &aMatrix) const
+nsSVGSVGElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                                          TransformTypes aWhich) const
 {
+  NS_ABORT_IF_FALSE(aWhich != eChildToUserSpace || aMatrix.IsIdentity(),
+                    "Skipping eUserSpaceToParent transforms makes no sense");
+
   if (IsInner()) {
     float x, y;
     const_cast<nsSVGSVGElement*>(this)->GetAnimatedLengthValues(&x, &y, nsnull);
-    return GetViewBoxTransform() * gfxMatrix().Translate(gfxPoint(x, y)) * aMatrix;
+    if (aWhich == eAllTransforms) {
+      // the common case
+      return GetViewBoxTransform() * gfxMatrix().Translate(gfxPoint(x, y)) * aMatrix;
+    }
+    if (aWhich == eUserSpaceToParent) {
+      return gfxMatrix().Translate(gfxPoint(x, y)) * aMatrix;
+    }
+    NS_ABORT_IF_FALSE(aWhich == eChildToUserSpace, "Unknown TransformTypes");
+    return GetViewBoxTransform(); // no need to multiply identity aMatrix
+  }
+
+  if (aWhich == eUserSpaceToParent) {
+    // only inner-<svg> has eUserSpaceToParent transforms
+    return aMatrix;
   }
 
   if (IsRoot()) {
     gfxMatrix zoomPanTM;
     zoomPanTM.Translate(gfxPoint(mCurrentTranslate.GetX(), mCurrentTranslate.GetY()));
     zoomPanTM.Scale(mCurrentScale, mCurrentScale);
     return GetViewBoxTransform() * zoomPanTM * aMatrix;
   }
--- a/content/svg/content/src/nsSVGSVGElement.h
+++ b/content/svg/content/src/nsSVGSVGElement.h
@@ -181,18 +181,19 @@ public:
 
   nsSMILTimeContainer* GetTimedDocumentRoot();
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   // nsSVGElement specializations:
-  virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix) const;
-  
+  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                      TransformTypes aWhich = eAllTransforms) const;
+ 
   // nsSVGSVGElement methods:
   float GetLength(PRUint8 mCtxType);
 
   // public helpers:
   gfxMatrix GetViewBoxTransform() const;
   bool      HasValidViewbox() const { return mViewBox.IsValid(); }
 
   // This services any pending notifications for the transform on on this root
--- a/content/svg/content/src/nsSVGUseElement.cpp
+++ b/content/svg/content/src/nsSVGUseElement.cpp
@@ -483,25 +483,37 @@ nsSVGUseElement::UnlinkSource()
   }
   mSource.Unlink();
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ gfxMatrix
-nsSVGUseElement::PrependLocalTransformTo(const gfxMatrix &aMatrix) const
+nsSVGUseElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                                          TransformTypes aWhich) const
 {
+  NS_ABORT_IF_FALSE(aWhich != eChildToUserSpace || aMatrix.IsIdentity(),
+                    "Skipping eUserSpaceToParent transforms makes no sense");
+
   // 'transform' attribute:
-  gfxMatrix matrix = nsSVGUseElementBase::PrependLocalTransformTo(aMatrix);
-
-  // now translate by our 'x' and 'y':
+  gfxMatrix fromUserSpace =
+    nsSVGUseElementBase::PrependLocalTransformsTo(aMatrix, aWhich);
+  if (aWhich == eUserSpaceToParent) {
+    return fromUserSpace;
+  }
+  // our 'x' and 'y' attributes:
   float x, y;
   const_cast<nsSVGUseElement*>(this)->GetAnimatedLengthValues(&x, &y, nsnull);
-  return matrix.PreMultiply(gfxMatrix().Translate(gfxPoint(x, y)));
+  gfxMatrix toUserSpace = gfxMatrix().Translate(gfxPoint(x, y));
+  if (aWhich == eChildToUserSpace) {
+    return toUserSpace;
+  }
+  NS_ABORT_IF_FALSE(aWhich == eAllTransforms, "Unknown TransformTypes");
+  return toUserSpace * fromUserSpace;
 }
 
 nsSVGElement::LengthAttributesInfo
 nsSVGUseElement::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
--- a/content/svg/content/src/nsSVGUseElement.h
+++ b/content/svg/content/src/nsSVGUseElement.h
@@ -98,17 +98,18 @@ public:
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGUseElementBase::)
 
   // for nsSVGUseFrame's nsIAnonymousContentCreator implementation.
   nsIContent* CreateAnonymousContent();
   nsIContent* GetAnonymousContent() const { return mClone; }
   void DestroyAnonymousContent();
 
   // nsSVGElement specializations:
-  virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix) const;
+  virtual gfxMatrix PrependLocalTransformsTo(const gfxMatrix &aMatrix,
+                      TransformTypes aWhich = eAllTransforms) const;
 
   // nsIContent interface
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   class SourceReference : public nsReferencedElement {
--- a/content/svg/content/test/bbox-helper.svg
+++ b/content/svg/content/test/bbox-helper.svg
@@ -1,12 +1,12 @@
 <?xml version="1.0"?>
 <svg xmlns="http://www.w3.org/2000/svg">
   <g transform="scale(0.5)">
-    <foreignObject id="f" width="100" height="100"/>
+    <foreignObject id="fO" x="10" y="10" width="100" height="100"/>
   </g>
   <text id="b" x="20" y="20">b</text>
   <text id="a" x="20" y="30">a</text>
   <text id="y" x="20" y="40">y</text>
   <g id="v">
     <circle cx="100" cy="50" r="5"/>
     <path d="M 100,100 L 100,200"/>
   </g>
--- a/content/svg/content/test/getCTM-helper.svg
+++ b/content/svg/content/test/getCTM-helper.svg
@@ -12,17 +12,17 @@
       <symbol id="sym" width="100" height="100">
         <rect id="symbolRect" width="0" height="0"
               transform="translate(70, 80)"/>
       </symbol>
     </defs>
     <svg id="inner" x="30" y="40" width="100" height="100">
       <g id="g1"/>
     </svg>
-    <foreignObject x="30" y="40" width="100" height="100" transform="translate(1, 1)">
+    <foreignObject id="fO" x="30" y="40" width="100" height="100" transform="translate(1, 1)">
       <!-- current layout implementation ignores x="50" and y="60".
            thus, I made getCTM and getScreenCTM do the same. -->
       <svg id="outer" x="50" y="60" width="100" height="100">
         <g id="g2" transform="translate(600, 700)"/>
       </svg>
     </foreignObject>
     <!-- something invalid -->
     <foreignObject>
--- a/content/svg/content/test/test_bbox.xhtml
+++ b/content/svg/content/test/test_bbox.xhtml
@@ -34,17 +34,17 @@ function run()
     is(bbox.height, height, id + ".getBBox().height");
   }
   function checkBBoxHeight(id1, id2) {
     var bbox1 = getBBox(id1);
     var bbox2 = getBBox(id2);
     is(bbox1.height, bbox2.height, id1 + ".getBBox().height");
   }
 
-  checkBBox("f", 0, 0, 100, 100);
+  checkBBox("fO", 10, 10, 100, 100);
   checkBBoxHeight("a", "b");
   checkBBoxHeight("a", "y");
   checkBBox("v", 95, 45, 10, 155);
   checkBBox("h", 195, 45, 105, 55);
   
   SimpleTest.finish();
 }
 
--- a/content/svg/content/test/test_getCTM.html
+++ b/content/svg/content/test/test_getCTM.html
@@ -32,16 +32,17 @@ function runTest()
   var inner = doc.getElementById("inner");
   var g1 = doc.getElementById("g1");
   var outer = doc.getElementById("outer");
   var g2 = doc.getElementById("g2");
   var g3 = doc.getElementById("g3");
   var g4 = doc.getElementById("g4");
   var sym = doc.getElementById("sym");
   var symbolRect = doc.getElementById("symbolRect");
+  var fO = doc.getElementById("fO");
   /* Tests the consistency with nearestViewportElement
      (code is from test_viewport.html) */
   // root.nearestViewportElement == null
   is((function(){try{return root.getCTM()}catch(e){return e}})(), null, "root.getCTM()");
   // inner.nearestViewportElement == root
   is((function(){try{return inner.getCTM().e}catch(e){return e}})(), 31, "inner.getCTM().e");
   is((function(){try{return inner.getCTM().f}catch(e){return e}})(), 42, "inner.getCTM().f");
   // g1.nearestViewportElement == inner
@@ -55,16 +56,19 @@ function runTest()
   // g3.nearestViewportElement == null
   is((function(){try{return g3.getCTM()}catch(e){return e}})(), null, "g3.getCTM()");
   // g4.nearestViewportElement == null
   is((function(){try{return g4.getCTM().e}catch(e){return e}})(), 1, "g4.getCTM().e");
   is((function(){try{return g4.getCTM().f}catch(e){return e}})(), 2, "g4.getCTM().f");
   // symbolRect.nearestViewportElement == sym
   is((function(){try{return symbolRect.getCTM().e}catch(e){return e}})(), 70, "symbolRect.getCTM().e");
   is((function(){try{return symbolRect.getCTM().f}catch(e){return e}})(), 80, "symbolRect.getCTM().f");
+  // fO.nearestViewportElement = <svg> with no 'id'
+  is((function(){try{return fO.getCTM().e}catch(e){return e}})(), 2, "fO.getCTM().e");
+  is((function(){try{return fO.getCTM().f}catch(e){return e}})(), 3, "fO.getCTM().f");
 
   /* Tests the consistency with farthestViewportElement
      (code is from test_viewport.html) */
   // root.farthestViewportElement == null (but actually == root)
   is((function(){try{return root.getScreenCTM().e}catch(e){return e}})(), 11, "root.getScreenCTM().e");
   is((function(){try{return root.getScreenCTM().f}catch(e){return e}})(), 22, "root.getScreenCTM().f");
   // inner.farthestViewportElement == root
   is((function(){try{return inner.getScreenCTM().e}catch(e){return e}})(), 45, "inner.getScreenCTM().e");
@@ -78,16 +82,19 @@ function runTest()
   // g2.farthestViewportElement == outer (but actually == root)
   is((function(){try{return g2.getScreenCTM().e}catch(e){return e}})(), 646, "g2.getScreenCTM().e");
   is((function(){try{return g2.getScreenCTM().f}catch(e){return e}})(), 769, "g2.getScreenCTM().f");
   // g3.farthestViewportElement == null (but actually == null)
   is((function(){try{return g3.getScreenCTM()}catch(e){return e}})(), null, "g3.getScreenCTM()");
   // symbolRect.farthestViewportElement == root
   is((function(){try{return symbolRect.getScreenCTM().e}catch(e){return e}})(), 85, "symbolRect.getScreenCTM().e");
   is((function(){try{return symbolRect.getScreenCTM().f}catch(e){return e}})(), 108, "symbolRect.getScreenCTM().f");
+  // fO.farthestViewportElement == root
+  is((function(){try{return fO.getScreenCTM().e}catch(e){return e}})(), 16, "symbolRect.getScreenCTM().e");
+  is((function(){try{return fO.getScreenCTM().f}catch(e){return e}})(), 29, "symbolRect.getScreenCTM().f");
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", runTest, false);
 </script>
 </pre>
 </body>
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4114,19 +4114,17 @@ nsDocShell::DisplayLoadError(nsresult aE
             error.get(),
             strs, formatStrCount, getter_Copies(str));
         NS_ENSURE_SUCCESS(rv, rv);
         messageStr.Assign(str.get());
     }
 
     // Display the error as a page or an alert prompt
     NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
-    // Note: For now, display an alert instead of an error page if we have no
-    // URI object. Missing URI objects are handled badly by session history.
-    if (mUseErrorPages && aURI) {
+    if (mUseErrorPages) {
         // Display an error page
         LoadErrorPage(aURI, aURL, errorPage.get(), error.get(),
                       messageStr.get(), cssClass.get(), aFailedChannel);
     } 
     else
     {
         // The prompter reqires that our private window has a document (or it
         // asserts). Satisfy that assertion now since GetDocument will force
@@ -4185,16 +4183,20 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, 
     if (aURI)
     {
         nsresult rv = aURI->GetSpec(url);
         rv |= aURI->GetOriginCharset(charset);
         NS_ENSURE_SUCCESS(rv, rv);
     }
     else if (aURL)
     {
+        // We need a URI object to store a session history entry, so make up a URI
+        nsresult rv = NS_NewURI(getter_AddRefs(mFailedURI), "about:blank");
+        NS_ENSURE_SUCCESS(rv, rv);
+
         CopyUTF16toUTF8(aURL, url);
     }
     else
     {
         return NS_ERROR_INVALID_POINTER;
     }
 
     // Create a URL to pass all the error information through to the page.
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -92,19 +92,14 @@ DIRS += \
 
 ifdef MOZ_B2G_RIL
 DIRS += \
   telephony \
   wifi \
   $(NULL)
 endif
 
-ifdef MOZ_B2G_BT
-DIRS += \
-  bluetooth \
-  $(NULL)
-endif
 TEST_DIRS += tests
 ifneq (,$(filter gtk2 cocoa windows android qt os2,$(MOZ_WIDGET_TOOLKIT)))
 TEST_DIRS += plugins/test
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -75,20 +75,16 @@
 #include "mozilla/Hal.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "Connection.h"
 
 #ifdef MOZ_B2G_RIL
 #include "TelephonyFactory.h"
 #endif
-#ifdef MOZ_B2G_BT
-#include "nsIDOMBluetoothAdapter.h"
-#include "BluetoothAdapter.h"
-#endif
 
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
 
 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
@@ -132,19 +128,16 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorBattery)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorDesktopNotification)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorSms)
 #ifdef MOZ_B2G_RIL
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorTelephony)
 #endif
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorNetwork)
-#ifdef MOZ_B2G_BT
-  NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorBluetooth)
-#endif
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(Navigator)
 NS_IMPL_RELEASE(Navigator)
 
 void
 Navigator::Invalidate()
@@ -184,22 +177,16 @@ Navigator::Invalidate()
     mTelephony = nsnull;
   }
 #endif
 
   if (mConnection) {
     mConnection->Shutdown();
     mConnection = nsnull;
   }
-
-#ifdef MOZ_B2G_BT
-  if (mBluetooth) {
-    mBluetooth = nsnull;
-  }
-#endif
 }
 
 nsPIDOMWindow *
 Navigator::GetWindow()
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
 
   return win;
@@ -1120,40 +1107,16 @@ Navigator::GetMozConnection(nsIDOMMozCon
     mConnection = new network::Connection();
     mConnection->Init(window, scx);
   }
 
   NS_ADDREF(*aConnection = mConnection);
   return NS_OK;
 }
 
-#ifdef MOZ_B2G_BT
-//*****************************************************************************
-//    nsNavigator::nsIDOMNavigatorBluetooth
-//*****************************************************************************
-
-NS_IMETHODIMP
-Navigator::GetMozBluetooth(nsIDOMBluetoothAdapter** aBluetooth)
-{
-  nsCOMPtr<nsIDOMBluetoothAdapter> bluetooth = mBluetooth;
-
-  if (!bluetooth) {
-    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
-    NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-    mBluetooth = new bluetooth::BluetoothAdapter();
-
-    bluetooth = mBluetooth;
-  }
-
-  bluetooth.forget(aBluetooth);
-  return NS_OK;
-}
-#endif //MOZ_B2G_BT
-
 PRInt64
 Navigator::SizeOf() const
 {
   PRInt64 size = sizeof(*this);
 
   // TODO: add SizeOf() to nsMimeTypeArray, bug 674113.
   size += mMimeTypes ? sizeof(*mMimeTypes.get()) : 0;
   // TODO: add SizeOf() to nsPluginArray, bug 674114.
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -60,21 +60,16 @@ class nsDesktopNotificationCenter;
 class nsPIDOMWindow;
 class nsIDOMMozConnection;
 
 #ifdef MOZ_B2G_RIL
 #include "nsIDOMNavigatorTelephony.h"
 class nsIDOMTelephony;
 #endif
 
-#ifdef MOZ_B2G_BT
-#include "nsIDOMNavigatorBluetooth.h"
-#endif
-
-class nsIDOMAdapter;
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
 namespace mozilla {
 namespace dom {
 
 namespace battery {
@@ -98,19 +93,16 @@ class Navigator : public nsIDOMNavigator
                 , public nsIDOMNavigatorGeolocation
                 , public nsIDOMNavigatorDesktopNotification
                 , public nsIDOMMozNavigatorBattery
                 , public nsIDOMMozNavigatorSms
 #ifdef MOZ_B2G_RIL
                 , public nsIDOMNavigatorTelephony
 #endif
                 , public nsIDOMMozNavigatorNetwork
-#ifdef MOZ_B2G_BT
-                , public nsIDOMNavigatorBluetooth
-#endif
 {
 public:
   Navigator(nsPIDOMWindow *aInnerWindow);
   virtual ~Navigator();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMNAVIGATOR
   NS_DECL_NSIDOMCLIENTINFORMATION
@@ -118,20 +110,16 @@ public:
   NS_DECL_NSIDOMNAVIGATORDESKTOPNOTIFICATION
   NS_DECL_NSIDOMMOZNAVIGATORBATTERY
   NS_DECL_NSIDOMMOZNAVIGATORSMS
 #ifdef MOZ_B2G_RIL
   NS_DECL_NSIDOMNAVIGATORTELEPHONY
 #endif
   NS_DECL_NSIDOMMOZNAVIGATORNETWORK
 
-#ifdef MOZ_B2G_BT
-  NS_DECL_NSIDOMNAVIGATORBLUETOOTH
-#endif
-
   static void Init();
 
   void Invalidate();
   nsPIDOMWindow *GetWindow();
 
   void RefreshMIMEArray();
 
   static bool HasDesktopNotificationSupport();
@@ -153,19 +141,16 @@ private:
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
   nsRefPtr<power::PowerManager> mPowerManager;
   nsRefPtr<sms::SmsManager> mSmsManager;
 #ifdef MOZ_B2G_RIL
   nsCOMPtr<nsIDOMTelephony> mTelephony;
 #endif
   nsRefPtr<network::Connection> mConnection;
-#ifdef MOZ_B2G_BT
-  nsCOMPtr<nsIDOMBluetoothAdapter> mBluetooth;
-#endif
   nsWeakPtr mWindow;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
 nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -527,20 +527,16 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "mozilla/dom/network/Utils.h"
 
 #ifdef MOZ_B2G_RIL
 #include "Telephony.h"
 #include "TelephonyCall.h"
 #include "CallEvent.h"
 #endif
 
-#ifdef MOZ_B2G_BT
-#include "BluetoothAdapter.h"
-#endif
-
 #include "DOMError.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
@@ -1626,21 +1622,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TelephonyCall, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
-#ifdef MOZ_B2G_BT
-  NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-#endif
-
   NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 };
 
 // Objects that should be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
@@ -2427,19 +2418,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorBattery,
                                         battery::BatteryManager::HasSupport())
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozNavigatorSms)
 #ifdef MOZ_B2G_RIL
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorTelephony)
 #endif
     DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorNetwork,
                                         network::IsAPIEnabled())
-#ifdef MOZ_B2G_BT
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorBluetooth)
-#endif
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(Plugin, nsIDOMPlugin)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPlugin)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(PluginArray, nsIDOMPluginArray)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPluginArray)
@@ -4372,22 +4360,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CallEvent, nsIDOMCallEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCallEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
   DOM_CLASSINFO_MAP_END
 #endif
 
-#ifdef MOZ_B2G_BT
-  DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
-  DOM_CLASSINFO_MAP_END
-#endif
-
   DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
   DOM_CLASSINFO_MAP_END
 
 #ifdef NS_DEBUG
   {
     PRUint32 i = ArrayLength(sClassInfoData);
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -535,13 +535,9 @@ DOMCI_CLASS(MediaQueryList)
 DOMCI_CLASS(CustomEvent)
 
 #ifdef MOZ_B2G_RIL
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 #endif
 
-#ifdef MOZ_B2G_BT
-DOMCI_CLASS(BluetoothAdapter)
-#endif
-
 DOMCI_CLASS(DOMError)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2087,16 +2087,23 @@ nsDOMWindowUtils::GetFileReferences(cons
   }
 
   *aRefCnt = *aDBRefCnt = *aSliceRefCnt = -1;
   *aResult = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::IsIncrementalGCEnabled(JSContext* cx, bool* aResult)
+{
+  *aResult = js::IsIncrementalGCEnabled(JS_GetRuntime(cx));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx)
 {
   js::StartPCCountProfiling(cx);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx)
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -130,16 +130,19 @@ static PRLogModuleInfo* gJSDiagnostics;
 #define NS_GC_DELAY                 4000 // ms
 
 #define NS_SHRINK_GC_BUFFERS_DELAY  4000 // ms
 
 // The amount of time we wait from the first request to GC to actually
 // doing the first GC.
 #define NS_FIRST_GC_DELAY           10000 // ms
 
+// Maximum amount of time that should elapse between incremental GC slices
+#define NS_INTERSLICE_GC_DELAY      100 // ms
+
 // The amount of time we wait between a request to CC (after GC ran)
 // and doing the actual CC.
 #define NS_CC_DELAY                 5000 // ms
 
 #define NS_CC_SKIPPABLE_DELAY       250 // ms
 
 #define NS_CC_FORCED                (5 * 60 * PR_USEC_PER_SEC) // 5 min
 
@@ -149,16 +152,19 @@ static PRLogModuleInfo* gJSDiagnostics;
 
 static nsITimer *sGCTimer;
 static nsITimer *sShrinkGCBuffersTimer;
 static nsITimer *sCCTimer;
 
 static PRTime sLastCCEndTime;
 
 static bool sGCHasRun;
+static bool sCCLockedOut;
+
+static js::GCSliceCallback sPrevGCSliceCallback;
 
 // The number of currently pending document loads. This count isn't
 // guaranteed to always reflect reality and can't easily as we don't
 // have an easy place to know when a load ends or is interrupted in
 // all cases. This counter also gets reset if we end up GC'ing while
 // we're waiting for a slow page to load. IOW, this count may be 0
 // even when there are pending loads.
 static PRUint32 sPendingLoadCount;
@@ -3269,16 +3275,21 @@ nsJSContext::ShrinkGCBuffersNow()
 void
 nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
                              PRInt32 aExtraForgetSkippableCalls)
 {
   if (!NS_IsMainThread()) {
     return;
   }
 
+  if (sCCLockedOut) {
+    // We're in the middle of an incremental GC; finish it first
+    nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
+  }
+
   SAMPLE_LABEL("GC", "CycleCollectNow");
   NS_TIME_FUNCTION_MIN(1.0);
 
   KillCCTimer();
 
   PRTime start = PR_Now();
 
   PRUint32 suspected = nsCycleCollector_suspectedCount();
@@ -3352,17 +3363,17 @@ nsJSContext::CycleCollectNow(nsICycleCol
 
 // static
 void
 GCTimerFired(nsITimer *aTimer, void *aClosure)
 {
   NS_RELEASE(sGCTimer);
 
   uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
-  nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCNormal);
+  nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCIncremental);
 }
 
 void
 ShrinkGCBuffersTimerFired(nsITimer *aTimer, void *aClosure)
 {
   NS_RELEASE(sShrinkGCBuffersTimer);
 
   nsJSContext::ShrinkGCBuffersNow();
@@ -3370,16 +3381,19 @@ ShrinkGCBuffersTimerFired(nsITimer *aTim
 
 // static
 void
 CCTimerFired(nsITimer *aTimer, void *aClosure)
 {
   if (sDidShutdown) {
     return;
   }
+  if (sCCLockedOut) {
+    return;
+  }
   ++sCCTimerFireCount;
   if (sCCTimerFireCount < (NS_CC_DELAY / NS_CC_SKIPPABLE_DELAY)) {
     PRUint32 suspected = nsCycleCollector_suspectedCount();
     if ((sPreviousSuspectedCount + 100) > suspected) {
       // Just few new suspected objects, return early.
       return;
     }
     
@@ -3438,36 +3452,38 @@ nsJSContext::LoadEnd()
 
   // Its probably a good idea to GC soon since we have finished loading.
   sLoadingInProgress = false;
   PokeGC(js::gcreason::LOAD_END);
 }
 
 // static
 void
-nsJSContext::PokeGC(js::gcreason::Reason aReason)
+nsJSContext::PokeGC(js::gcreason::Reason aReason, int aDelay)
 {
   if (sGCTimer) {
     // There's already a timer for GC'ing, just return
     return;
   }
 
   CallCreateInstance("@mozilla.org/timer;1", &sGCTimer);
 
   if (!sGCTimer) {
     // Failed to create timer (probably because we're in XPCOM shutdown)
     return;
   }
 
   static bool first = true;
 
   sGCTimer->InitWithFuncCallback(GCTimerFired, reinterpret_cast<void *>(aReason),
-                                 first
-                                 ? NS_FIRST_GC_DELAY
-                                 : NS_GC_DELAY,
+                                 aDelay
+                                 ? aDelay
+                                 : (first
+                                    ? NS_FIRST_GC_DELAY
+                                    : NS_GC_DELAY),
                                  nsITimer::TYPE_ONE_SHOT);
 
   first = false;
 }
 
 // static
 void
 nsJSContext::PokeShrinkGCBuffers()
@@ -3544,71 +3560,92 @@ nsJSContext::KillCCTimer()
 
 void
 nsJSContext::GC(js::gcreason::Reason aReason)
 {
   PokeGC(aReason);
 }
 
 static void
-DOMGCFinishedCallback(JSRuntime *rt, JSCompartment *comp, const char *status)
+DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescription &aDesc)
 {
   NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
 
-  if (sPostGCEventsToConsole) {
+  if (aDesc.logMessage && sPostGCEventsToConsole) {
     PRTime now = PR_Now();
     PRTime delta = 0;
     if (sFirstCollectionTime) {
       delta = now - sFirstCollectionTime;
     } else {
       sFirstCollectionTime = now;
     }
 
     NS_NAMED_LITERAL_STRING(kFmt, "GC(T+%.1f) %s");
     nsString msg;
     msg.Adopt(nsTextFormatter::smprintf(kFmt.get(),
-                                        double(delta) / PR_USEC_PER_SEC, status));
+                                        double(delta) / PR_USEC_PER_SEC,
+                                        aDesc.logMessage));
     nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     if (cs) {
       cs->LogStringMessage(msg.get());
     }
   }
 
-  sCCollectedWaitingForGC = 0;
-  sCleanupSinceLastGC = false;
-
-  if (sGCTimer) {
-    // If we were waiting for a GC to happen, kill the timer.
+  // Prevent cycle collections during incremental GC.
+  if (aProgress == js::GC_CYCLE_BEGIN) {
+    sCCLockedOut = true;
+  } else if (aProgress == js::GC_CYCLE_END) {
+    sCCLockedOut = false;
+  }
+
+  // The GC has more work to do, so schedule another GC slice.
+  if (aProgress == js::GC_SLICE_END) {
     nsJSContext::KillGCTimer();
-
-    // If this is a compartment GC, restart it. We still want
-    // a full GC to happen. Compartment GCs usually happen as a
-    // result of last-ditch or MaybeGC. In both cases its
-    // probably a time of heavy activity and we want to delay
-    // the full GC, but we do want it to happen eventually.
-    if (comp) {
-      nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
-
-      // We poked the GC, so we can kill any pending CC here.
-      nsJSContext::KillCCTimer();
+    nsJSContext::KillCCTimer();
+
+    nsJSContext::PokeGC(js::gcreason::INTER_SLICE_GC, NS_INTERSLICE_GC_DELAY);
+  }
+
+  if (aProgress == js::GC_CYCLE_END) {
+    sCCollectedWaitingForGC = 0;
+    sCleanupSinceLastGC = false;
+
+    if (sGCTimer) {
+      // If we were waiting for a GC to happen, kill the timer.
+      nsJSContext::KillGCTimer();
+
+      // If this is a compartment GC, restart it. We still want
+      // a full GC to happen. Compartment GCs usually happen as a
+      // result of last-ditch or MaybeGC. In both cases its
+      // probably a time of heavy activity and we want to delay
+      // the full GC, but we do want it to happen eventually.
+      if (aDesc.isCompartment) {
+        nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
+
+        // We poked the GC, so we can kill any pending CC here.
+        nsJSContext::KillCCTimer();
+      }
+    } else {
+      // If this was a full GC, poke the CC to run soon.
+      if (!aDesc.isCompartment) {
+        sGCHasRun = true;
+        nsJSContext::MaybePokeCC();
+      }
     }
-  } else {
-    // If this was a full GC, poke the CC to run soon.
-    if (!comp) {
-      sGCHasRun = true;
-      nsJSContext::MaybePokeCC();
+
+    // If we didn't end up scheduling a GC, make sure that we release GC buffers
+    // soon after canceling previous shrinking attempt.
+    nsJSContext::KillShrinkGCBuffersTimer();
+    if (!sGCTimer) {
+      nsJSContext::PokeShrinkGCBuffers();
     }
   }
 
-  // If we didn't end up scheduling a GC, make sure that we release GC buffers
-  // soon after canceling previous shrinking attempt 
-  nsJSContext::KillShrinkGCBuffersTimer();
-  if (!sGCTimer) {
-    nsJSContext::PokeShrinkGCBuffers();
-  }
+  if (sPrevGCSliceCallback)
+    (*sPrevGCSliceCallback)(aRt, aProgress, aDesc);
 }
 
 // Script object mananagement - note duplicate implementation
 // in nsJSRuntime below...
 nsresult
 nsJSContext::HoldScriptObject(void* aScriptObject)
 {
     NS_ASSERTION(sIsInitialized, "runtime not initialized");
@@ -3692,16 +3729,17 @@ nsJSRuntime::ParseVersion(const nsString
 
 //static
 void
 nsJSRuntime::Startup()
 {
   // initialize all our statics, so that we can restart XPCOM
   sGCTimer = sCCTimer = nsnull;
   sGCHasRun = false;
+  sCCLockedOut = false;
   sLastCCEndTime = 0;
   sPendingLoadCount = 0;
   sLoadingInProgress = false;
   sCCollectedWaitingForGC = 0;
   sPostGCEventsToConsole = false;
   gNameSpaceManager = nsnull;
   sRuntimeService = nsnull;
   sRuntime = nsnull;
@@ -3763,20 +3801,37 @@ SetMemoryMaxPrefChangedCallback(const ch
   PRUint32 max = (pref <= 0 || pref >= 0x1000) ? -1 : (PRUint32)pref * 1024 * 1024;
   JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MAX_BYTES, max);
   return 0;
 }
 
 static int
 SetMemoryGCModePrefChangedCallback(const char* aPrefName, void* aClosure)
 {
-  bool enableCompartmentGC = Preferences::GetBool(aPrefName);
-  JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MODE, enableCompartmentGC
-                                                      ? JSGC_MODE_COMPARTMENT
-                                                      : JSGC_MODE_GLOBAL);
+  PRBool enableCompartmentGC = Preferences::GetBool("javascript.options.mem.gc_per_compartment");
+  PRBool enableIncrementalGC = Preferences::GetBool("javascript.options.mem.gc_incremental");
+  JSGCMode mode;
+  if (enableIncrementalGC) {
+    mode = JSGC_MODE_INCREMENTAL;
+  } else if (enableCompartmentGC) {
+    mode = JSGC_MODE_COMPARTMENT;
+  } else {
+    mode = JSGC_MODE_GLOBAL;
+  }
+  JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MODE, mode);
+  return 0;
+}
+
+static int
+SetMemoryGCSliceTimePrefChangedCallback(const char* aPrefName, void* aClosure)
+{
+  PRInt32 pref = Preferences::GetInt(aPrefName, -1);
+  // handle overflow and negative pref values
+  if (pref > 0 && pref < 100000)
+    JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_SLICE_TIME_BUDGET, pref);
   return 0;
 }
 
 static JSPrincipals *
 ObjectPrincipalFinder(JSContext *cx, JSObject *obj)
 {
   if (!sSecurityManager)
     return nsnull;
@@ -3853,17 +3908,17 @@ nsJSRuntime::Init()
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = sRuntimeService->GetRuntime(&sRuntime);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Let's make sure that our main thread is the same as the xpcom main thread.
   NS_ASSERTION(NS_IsMainThread(), "bad");
 
-  ::JS_SetGCFinishedCallback(sRuntime, DOMGCFinishedCallback);
+  sPrevGCSliceCallback = js::SetGCSliceCallback(sRuntime, DOMGCSliceCallback);
 
   JSSecurityCallbacks *callbacks = JS_GetRuntimeSecurityCallbacks(sRuntime);
   NS_ASSERTION(callbacks, "SecMan should have set security callbacks!");
 
   callbacks->findObjectPrincipals = ObjectPrincipalFinder;
 
   // Set up the structured clone callbacks.
   static JSStructuredCloneCallbacks cloneCallbacks = {
@@ -3898,16 +3953,26 @@ nsJSRuntime::Init()
   SetMemoryMaxPrefChangedCallback("javascript.options.mem.max",
                                   nsnull);
 
   Preferences::RegisterCallback(SetMemoryGCModePrefChangedCallback,
                                 "javascript.options.mem.gc_per_compartment");
   SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_per_compartment",
                                      nsnull);
 
+  Preferences::RegisterCallback(SetMemoryGCModePrefChangedCallback,
+                                "javascript.options.mem.gc_incremental");
+  SetMemoryGCModePrefChangedCallback("javascript.options.mem.gc_incremental",
+                                     nsnull);
+
+  Preferences::RegisterCallback(SetMemoryGCSliceTimePrefChangedCallback,
+                                "javascript.options.mem.gc_incremental_slice_ms");
+  SetMemoryGCSliceTimePrefChangedCallback("javascript.options.mem.gc_incremental_slice_ms",
+                                          nsnull);
+
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (!obs)
     return NS_ERROR_FAILURE;
 
   Preferences::AddBoolVarCache(&sGCOnMemoryPressure,
                                "javascript.options.gc_on_memory_pressure",
                                true);
 
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -183,17 +183,17 @@ public:
 
   static void GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind = nsGCNormal);
   static void ShrinkGCBuffersNow();
   // If aExtraForgetSkippableCalls is -1, forgetSkippable won't be
   // called even if the previous collection was GC.
   static void CycleCollectNow(nsICycleCollectorListener *aListener = nsnull,
                               PRInt32 aExtraForgetSkippableCalls = 0);
 
-  static void PokeGC(js::gcreason::Reason aReason);
+  static void PokeGC(js::gcreason::Reason aReason, int aDelay = 0);
   static void KillGCTimer();
 
   static void PokeShrinkGCBuffers();
   static void KillShrinkGCBuffersTimer();
 
   static void MaybePokeCC();
   static void KillCCTimer();
 
deleted file mode 100644
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=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/. */
-
-#include "BluetoothAdapter.h"
-#include "nsDOMClassInfo.h"
-
-USING_BLUETOOTH_NAMESPACE
-
-BluetoothAdapter::BluetoothAdapter() : mPower(false)
-{
-}
-
-NS_INTERFACE_MAP_BEGIN(BluetoothAdapter)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
-NS_INTERFACE_MAP_END
-  
-NS_IMPL_ADDREF(BluetoothAdapter)
-NS_IMPL_RELEASE(BluetoothAdapter)
-
-DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
-  
-NS_IMETHODIMP
-BluetoothAdapter::GetPower(bool* aPower)
-{
-  *aPower = mPower;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::SetPower(bool aPower)
-{
-  mPower = aPower;
-  return NS_OK;
-}
deleted file mode 100644
--- a/dom/bluetooth/BluetoothAdapter.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=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/. */
-
-#ifndef mozilla_dom_bluetooth_bluetoothadapter_h__
-#define mozilla_dom_bluetooth_bluetoothadapter_h__
-
-#include "BluetoothCommon.h"
-#include "nsIDOMBluetoothAdapter.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-class BluetoothAdapter : public nsIDOMBluetoothAdapter
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMBLUETOOTHADAPTER
-
-  BluetoothAdapter();
-
-protected:
-  bool mPower;
-};
-
-END_BLUETOOTH_NAMESPACE
-#endif
deleted file mode 100644
--- a/dom/bluetooth/BluetoothCommon.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=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/. */
-
-#ifndef mozilla_dom_bluetooth_bluetoothcommon_h__
-#define mozilla_dom_bluetooth_bluetoothcommon_h__
-
-#define BEGIN_BLUETOOTH_NAMESPACE \
-  namespace mozilla { namespace dom { namespace bluetooth {
-#define END_BLUETOOTH_NAMESPACE \
-  } /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */
-#define USING_BLUETOOTH_NAMESPACE \
-  using namespace mozilla::dom::bluetooth;
-
-class nsIDOMBluetooth;
-
-#endif // mozilla_dom_bluetooth_bluetoothcommon_h__
deleted file mode 100644
--- a/dom/bluetooth/Makefile.in
+++ /dev/null
@@ -1,30 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEPTH            = ../..
-topsrcdir        = @top_srcdir@
-srcdir           = @srcdir@
-VPATH            = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE           = dom
-LIBRARY_NAME     = dombluetooth_s
-XPIDL_MODULE     = dom_bluetooth
-LIBXUL_LIBRARY   = 1
-FORCE_STATIC_LIB = 1
-
-include $(topsrcdir)/dom/dom-config.mk
-
-CPPSRCS = \
-  BluetoothAdapter.cpp \
-  $(NULL)
-
-XPIDLSRCS = \
-  nsIDOMNavigatorBluetooth.idl \
-  nsIDOMBluetoothAdapter.idl \
-  $(NULL)
-
-include $(topsrcdir)/config/rules.mk
-
deleted file mode 100644
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=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/. */
-
-#include "nsISupports.idl"
-
-[scriptable, builtinclass, uuid(29689a22-45ff-4ccf-b552-5364ce3a3642)]
-interface nsIDOMBluetoothAdapter : nsISupports
-{
-  attribute boolean power;
-};
deleted file mode 100644
--- a/dom/bluetooth/nsIDOMNavigatorBluetooth.idl
+++ /dev/null
@@ -1,15 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=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/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMBluetoothAdapter;
-
-[scriptable, uuid(677f2c2d-c4d1-41ea-addc-21d30d0d3858)]
-interface nsIDOMNavigatorBluetooth : nsISupports
-{
-  readonly attribute nsIDOMBluetoothAdapter mozBluetooth;
-};
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -26,14 +26,10 @@ DOM_SRCDIRS = \
 ifdef MOZ_B2G_RIL
 DOM_SRCDIRS += \
   dom/system/b2g \
   dom/telephony \
   dom/wifi \
   $(NULL)
 endif
 
-ifdef MOZ_B2G_BT
-DOM_SRCDIRS += dom/bluetooth
-endif
-
 LOCAL_INCLUDES += $(DOM_SRCDIRS:%=-I$(topsrcdir)/%)
 DEFINES += -D_IMPL_NS_LAYOUT
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -65,17 +65,17 @@ interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 
-[scriptable, uuid(ab6e9c71-8aa1-40bb-8bf9-65e16429055f)]
+[scriptable, uuid(73b48170-55d5-11e1-b86c-0800200c9a66)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -988,16 +988,22 @@ interface nsIDOMWindowUtils : nsISupport
    *
    */
   boolean getFileReferences(in AString aDatabaseName, in long long aId,
                             [optional] out long aRefCnt,
                             [optional] out long aDBRefCnt,
                             [optional] out long aSliceRefCnt);
 
   /**
+   * Return whether incremental GC has been disabled due to a binary add-on.
+   */
+  [implicit_jscontext]
+  boolean isIncrementalGCEnabled();
+
+  /**
    * Begin opcode-level profiling of all JavaScript execution in the window's
    * runtime.
    */
   [implicit_jscontext]
   void startPCCountProfiling();
 
   /**
    * Stop opcode-level profiling of JavaScript execution in the runtime, and
--- a/dom/interfaces/css/nsIDOMCSSStyleDeclaration.idl
+++ b/dom/interfaces/css/nsIDOMCSSStyleDeclaration.idl
@@ -55,14 +55,14 @@ interface nsIDOMCSSStyleDeclaration : ns
 
   DOMString          getPropertyValue(in DOMString propertyName);
   nsIDOMCSSValue     getPropertyCSSValue(in DOMString propertyName);
   DOMString          removeProperty(in DOMString propertyName)
                                         raises(DOMException);
   DOMString          getPropertyPriority(in DOMString propertyName);
   void               setProperty(in DOMString propertyName, 
                                  in DOMString value, 
-                                 in DOMString priority)
+                                 [optional] in DOMString priority)
                                         raises(DOMException);
   readonly attribute unsigned long    length;
   DOMString          item(in unsigned long index);
   readonly attribute nsIDOMCSSRule    parentRule;
 };
--- a/dom/interfaces/events/nsIDOMNSEvent.idl
+++ b/dom/interfaces/events/nsIDOMNSEvent.idl
@@ -39,17 +39,17 @@
 #include "domstubs.idl"
 
 %{C++
 #ifdef ERROR
 #undef ERROR
 #endif
 %}
 
-[scriptable, uuid(9be8096b-f795-4045-9664-0c275f36fe5b)]
+[scriptable, uuid(07F905C1-9170-4103-86CA-766374DA149A)]
 interface nsIDOMNSEvent : nsISupports
 {
   const long MOUSEDOWN    = 0x00000001;
   const long MOUSEUP      = 0x00000002;
   const long MOUSEOVER    = 0x00000004;
   const long MOUSEOUT     = 0x00000008;
   const long MOUSEMOVE    = 0x00000010;
   const long MOUSEDRAG    = 0x00000020;
@@ -92,22 +92,16 @@ interface nsIDOMNSEvent : nsISupports
    * to the target before the retargeting occurs.  For example, mouse events
    * are retargeted to their parent node when they happen over text nodes (bug
    * 185889), and in that case .target will show the parent and
    * .explicitOriginalTarget will show the text node.
    * .explicitOriginalTarget differs from .originalTarget in that it will never
    * contain anonymous content.
    */
   readonly attribute nsIDOMEventTarget  explicitOriginalTarget;
-  /* XXX This is TEMPORARY.  
-   * The original target, without any retargeting (like textnode retargeting).
-   * This really needs to be in .originalTarget, but this is a less risky way of
-   * fixing it.
-   */
-  [noscript] readonly attribute nsIDOMEventTarget  tmpRealOriginalTarget;
 
   /**
    * @deprecated Use nsIDOMEvent::stopPropagation.
    */
   void                      preventBubble();
 
   /**
    * @deprecated Use nsIDOMEvent::stopPropagation.
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -174,17 +174,17 @@ NPObjWrapper_Construct(JSContext *cx, ui
 
 static JSBool
 CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject *npobj,
                      jsid id, NPVariant* getPropertyResult, jsval *vp);
 
 static JSClass sNPObjectJSWrapperClass =
   {
     NPRUNTIME_JSCLASS_NAME,
-    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE,
+    JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE,
     NPObjWrapper_AddProperty, NPObjWrapper_DelProperty,
     NPObjWrapper_GetProperty, NPObjWrapper_SetProperty,
     (JSEnumerateOp)NPObjWrapper_newEnumerate,
     (JSResolveOp)NPObjWrapper_NewResolve, NPObjWrapper_Convert,
     NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call,
     NPObjWrapper_Construct, nsnull, nsnull
   };
 
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -3110,18 +3110,23 @@ nsresult nsPluginHost::NewPluginURLStrea
       // Plug-ins seem to depend on javascript: URIs running synchronously
       scriptChannel->SetExecuteAsync(false);
     }
   }
 
   // deal with headers and post data
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
-    rv = httpChannel->SetReferrer(doc->GetDocumentURI());  
-    NS_ENSURE_SUCCESS(rv,rv);
+    if (!aPostStream) {
+      // Only set the Referer header for GET requests because IIS throws
+      // errors about malformed requests if we include it in POSTs. See
+      // bug 724465.
+      rv = httpChannel->SetReferrer(doc->GetDocumentURI());  
+      NS_ENSURE_SUCCESS(rv,rv);
+    }
       
     if (aPostStream) {
       // XXX it's a bit of a hack to rewind the postdata stream
       // here but it has to be done in case the post data is
       // being reused multiple times.
       nsCOMPtr<nsISeekableStream>
       postDataSeekable(do_QueryInterface(aPostStream));
       if (postDataSeekable)
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1385,75 +1385,74 @@ void nsPluginInstanceOwner::CARefresh(ns
     r.left = 0;
     r.top = 0;
     r.right = window->width;
     r.bottom = window->height; 
     instanceOwner->InvalidateRect(&r);
   }
 }
 
-void nsPluginInstanceOwner::AddToCARefreshTimer(nsPluginInstanceOwner *aPluginInstance) {
+void nsPluginInstanceOwner::AddToCARefreshTimer() {
+  if (!mInstance) {
+    return;
+  }
+
+  // Flash invokes InvalidateRect for us.
+  const char* mime = nsnull;
+  if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime) {
+    if (strcmp(mime, "application/x-shockwave-flash") == 0) {
+      return;
+    }
+  }
+
   if (!sCARefreshListeners) {
     sCARefreshListeners = new nsTArray<nsPluginInstanceOwner*>();
     if (!sCARefreshListeners) {
       return;
     }
   }
 
-  NS_ASSERTION(!sCARefreshListeners->Contains(aPluginInstance), 
-      "pluginInstanceOwner already registered as a listener");
-  sCARefreshListeners->AppendElement(aPluginInstance);
+  if (sCARefreshListeners->Contains(this)) {
+    return;
+  }
+
+  sCARefreshListeners->AppendElement(this);
 
   if (!sCATimer) {
     sCATimer = new nsCOMPtr<nsITimer>();
     if (!sCATimer) {
       return;
     }
   }
 
   if (sCARefreshListeners->Length() == 1) {
     *sCATimer = do_CreateInstance("@mozilla.org/timer;1");
     (*sCATimer)->InitWithFuncCallback(CARefresh, NULL, 
                    DEFAULT_REFRESH_RATE, nsITimer::TYPE_REPEATING_SLACK);
   }
 }
 
-void nsPluginInstanceOwner::RemoveFromCARefreshTimer(nsPluginInstanceOwner *aPluginInstance) {
-  if (!sCARefreshListeners || sCARefreshListeners->Contains(aPluginInstance) == false) {
+void nsPluginInstanceOwner::RemoveFromCARefreshTimer() {
+  if (!sCARefreshListeners || sCARefreshListeners->Contains(this) == false) {
     return;
   }
 
-  sCARefreshListeners->RemoveElement(aPluginInstance);
+  sCARefreshListeners->RemoveElement(this);
 
   if (sCARefreshListeners->Length() == 0) {
     if (sCATimer) {
       (*sCATimer)->Cancel();
       delete sCATimer;
       sCATimer = NULL;
     }
     delete sCARefreshListeners;
     sCARefreshListeners = NULL;
   }
 }
 
-void nsPluginInstanceOwner::SetupCARefresh()
-{
-  if (!mInstance) {
-    return;
-  }
-
-  const char* mime = nsnull;
-  if (NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime) {
-    // Flash invokes InvalidateRect for us.
-    if (strcmp(mime, "application/x-shockwave-flash") != 0) {
-    AddToCARefreshTimer(this);
-  }
-}
-}
-
 void nsPluginInstanceOwner::RenderCoreAnimation(CGContextRef aCGContext,
                                                 int aWidth, int aHeight)
 {
   if (aWidth == 0 || aHeight == 0)
     return;
 
   if (!mIOSurface ||
       (mIOSurface->GetWidth() != (size_t)aWidth ||
@@ -2694,17 +2693,17 @@ nsPluginInstanceOwner::Destroy()
   if (mObjectFrame)
     mObjectFrame->SetInstanceOwner(nsnull);
 
 #ifdef MAC_CARBON_PLUGINS
   // stop the timer explicitly to reduce reference count.
   CancelTimer();
 #endif
 #ifdef XP_MACOSX
-  RemoveFromCARefreshTimer(this);
+  RemoveFromCARefreshTimer();
   if (mColorProfile)
     ::CGColorSpaceRelease(mColorProfile);  
 #endif
 
   // unregister context menu listener
   if (mCXMenuListener) {
     mCXMenuListener->Destroy(mContent);
     mCXMenuListener = nsnull;
@@ -3272,17 +3271,17 @@ void nsPluginInstanceOwner::ReleasePlugi
   }
 #endif
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
 {
   NS_ENSURE_TRUE(mPluginWindow, NS_ERROR_NULL_POINTER);
 
-    nsresult rv = NS_ERROR_FAILURE;
+  nsresult rv = NS_ERROR_FAILURE;
   
   // Can't call this twice!
   if (mWidget) {
     NS_WARNING("Trying to create a plugin widget twice!");
     return NS_ERROR_FAILURE;
   }
   
   bool windowless = false;
@@ -3313,16 +3312,31 @@ NS_IMETHODIMP nsPluginInstanceOwner::Cre
       mWidget->Destroy();
       mWidget = nsnull;
       return rv;
     }
 
     mWidget->EnableDragDrop(true);
     mWidget->Show(false);
     mWidget->Enable(false);
+
+#ifdef XP_MACOSX
+    // Now that we have a widget we want to set the event model before
+    // any events are processed.
+    nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
+    if (!pluginWidget) {
+      return NS_ERROR_FAILURE;
+    }
+    pluginWidget->SetPluginEventModel(GetEventModel());
+    pluginWidget->SetPluginDrawingModel(GetDrawingModel());
+
+    if (GetDrawingModel() == NPDrawingModelCoreAnimation) {
+      AddToCARefreshTimer();
+    }
+#endif
   }
 
   if (mObjectFrame) {
     // NULL widget is fine, will result in windowless setup.
     mObjectFrame->PrepForDrawing(mWidget);
   }
 
   if (windowless) {
@@ -3664,42 +3678,52 @@ void nsPluginInstanceOwner::SetFrame(nsO
         // called, so OnDestroyImage() can't yet have been called.  So we need
         // to do ourselves what OnDestroyImage() would have done.
         NS_RELEASE_THIS();
       }
 #endif
       container->SetCurrentImage(nsnull);
     }
 
-    // If we had an old frame and we're not going to have a new one then
-    // we should unregister for some things.
+#if defined(XP_MACOSX) && !defined(NP_NO_QUICKDRAW)
     if (!aFrame) {
-      // Unregister scroll position listeners
+      // At this point we had a frame but it is going away and we're not getting a new one.
+      // Unregister for a scroll position listening, which is only required for Carbon
+      // event model plugins on Mac OS X. It's OK to unregister when we didn't register,
+      // so don't be strict about unregistering. Better to unregister when we didn't have to
+      // than to not unregister when we should.
       for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
         nsIScrollableFrame* sf = do_QueryFrame(f);
         if (sf) {
           sf->RemoveScrollPositionListener(this);
         }
       }
     }
+#endif
 
     // Make sure the old frame isn't holding a reference to us.
     mObjectFrame->SetInstanceOwner(nsnull);
   } else {
+    // Scroll position listening is only required for Carbon event model plugins on Mac OS X.
+    // Note that we probably have a crash bug in the way we register/unregister, bug 723190.
+    // Bug 723190 is mitigated by limiting registration to Carbon event model plugins.
+#if defined(XP_MACOSX) && !defined(NP_NO_QUICKDRAW)
     if (aFrame) {
-      // We didn't have an object frame before but we do now!
-      // We need to register a scroll position listener on every scrollable
-      // frame up to the top
-      for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
-        nsIScrollableFrame* sf = do_QueryFrame(f);
-        if (sf) {
-          sf->AddScrollPositionListener(this);
+      // We didn't have an object frame before but we do now. We need to register a scroll
+      // position listener on every scrollable frame up to the top.
+      if (GetEventModel() == NPEventModelCarbon) {
+        for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
+          nsIScrollableFrame* sf = do_QueryFrame(f);
+          if (sf) {
+            sf->AddScrollPositionListener(this);
+          }
         }
       }
     }
+#endif
   }
 
   // Swap in the new frame (or no frame)
   mObjectFrame = aFrame;
 
   // Set up a new frame
   if (mObjectFrame) {
     mObjectFrame->SetInstanceOwner(this);
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -177,19 +177,18 @@ public:
   
 #ifdef XP_MACOSX
   enum { ePluginPaintEnable, ePluginPaintDisable };
   
   NPDrawingModel GetDrawingModel();
   bool IsRemoteDrawingCoreAnimation();
   NPEventModel GetEventModel();
   static void CARefresh(nsITimer *aTimer, void *aClosure);
-  static void AddToCARefreshTimer(nsPluginInstanceOwner *aPluginInstance);
-  static void RemoveFromCARefreshTimer(nsPluginInstanceOwner *aPluginInstance);
-  void SetupCARefresh();
+  void AddToCARefreshTimer();
+  void RemoveFromCARefreshTimer();
   // This calls into the plugin (NPP_SetWindow) and can run script.
   void* FixUpPluginWindow(PRInt32 inPaintState);
   void HidePluginWindow();
   // Set a flag that (if true) indicates the plugin port info has changed and
   // SetWindow() needs to be called.
   void SetPluginPortChanged(bool aState) { mPluginPortChanged = aState; }
   // Return a pointer to the internal nsPluginPort structure that's used to
   // store a copy of plugin port info and to detect when it's been changed.
--- a/dom/plugins/test/mochitest/Makefile.in
+++ b/dom/plugins/test/mochitest/Makefile.in
@@ -104,16 +104,18 @@ include $(topsrcdir)/config/rules.mk
   test_zero_opacity.html \
   test_NPPVpluginWantsAllNetworkStreams.html \
   test_npruntime_npnsetexception.html \
   test_NPNVdocumentOrigin.html \
   test_instance_re-parent.html \
   test_instance_unparent1.html \
   test_instance_unparent2.html \
   test_instance_unparent3.html \
+  test_pluginstream_referer.html \
+  plugin-stream-referer.sjs \
   $(NULL)
 
 #  test_plugin_scroll_painting.html \ bug 596491
 
 ifeq ($(OS_ARCH),WINNT)
 _MOCHITEST_FILES += \
   test_windowed_invalidate.html \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin-stream-referer.sjs
@@ -0,0 +1,10 @@
+function handleRequest(request, response)
+{
+  response.setHeader('Content-Type', 'text/plain', false);
+  if (request.hasHeader('Referer')) {
+    response.write('Referer found: ' + request.getHeader('Referer'));
+  }
+  else {
+    response.write('No Referer found');
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_referer.html
@@ -0,0 +1,42 @@
+<head>
+  <title>Do plugin stream requests send the Referer header correctly?</title>
+  <script type="application/javascript"
+	  src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" 
+        href="/tests/SimpleTest/test.css" />
+
+<body onload="runTests()">
+  <p id="display"></p>
+
+  <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+
+  <script class="testbody" type="application/javascript">
+  SimpleTest.waitForExplicitFinish();
+
+  var pending = 2;
+  function testDone() {
+    --pending;
+    if (0 == pending)
+      SimpleTest.finish()
+  }
+
+  function runTests() {
+    var p = document.getElementById('plugin1');
+
+    ok(p.streamTest('plugin-stream-referer.sjs', false, null, null,
+                    function(r, t) {
+                      is(r, 0, "GET plugin-stream-referer.sjs");
+                      is(t, "Referer found: " + window.location,
+                         "GET Referer correct");
+                      testDone();
+                    }, null, true), "referer GET");
+
+    ok(p.streamTest('plugin-stream-referer.sjs', true, "Dummy Data", null,
+                    function(r, t) {
+                      is(r, 0, "POST plugin-stream-referer.sjs");
+                      is(t, "No Referer found", "POST Referer absent");
+                      testDone();
+                    }, null, true), "referer POST");
+  }
+  </script>
+
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -228,16 +228,18 @@ nsJSEventListener::HandleEvent(nsIDOMEve
   JSContext* cx = nsnull;
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
   NS_ASSERTION(stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx &&
                GetScriptContextFromJSContext(cx) == mContext,
                "JSEventListener has wrong script context?");
 #endif
   nsCOMPtr<nsIVariant> vrv;
+  xpc_UnmarkGrayObject(mScopeObject);
+  xpc_UnmarkGrayObject(mHandler);
   rv = mContext->CallEventHandler(mTarget, mScopeObject, mHandler, iargv,
                                   getter_AddRefs(vrv));
 
   if (NS_SUCCEEDED(rv)) {
     PRUint16 dataType = nsIDataType::VTYPE_VOID;
     if (vrv)
       vrv->GetDataType(&dataType);
 
--- a/dom/wifi/nsIWifi.idl
+++ b/dom/wifi/nsIWifi.idl
@@ -14,17 +14,17 @@
  * The Original Code is Telephony.
  *
  * The Initial Developer of the Original Code is
  * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *  Philipp von Weitershausen <philipp@weitershausen.de>
+ *  Blake Kaplan <mrbkap@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -32,11 +32,19 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
+[scriptable, uuid(14c815f0-e9db-41d4-a15e-f3e69140f83b)]
+interface nsIWifiNetwork : nsISupports {
+    readonly attribute DOMString ssid; // can be null
+    readonly attribute DOMString bssid; // can be null
+    readonly attribute DOMString flags; // TODO make this be real flags instead of a string
+    readonly attribute long signal;
+};
+
 [scriptable, uuid(9DCE05BF-659C-4427-A050-0EAC3BB6C1C0)]
 interface nsIWifi : nsISupports {
 };
--- a/dom/wifi/nsWifiWorker.js
+++ b/dom/wifi/nsWifiWorker.js
@@ -790,82 +790,110 @@ var WifiManager = (function() {
   manager.disableNetwork = function(netId, callback) {
     disableNetworkCommand(netId, callback);
   }
   manager.getMacAddress = getMacAddressCommand;
   manager.getScanResults = scanResultsCommand;
   return manager;
 })();
 
+function WifiNetwork(ssid, bssid, flags, signal) {
+  this.ssid = ssid;
+  this.bssid = bssid;
+  this.flags = flags;
+  this.signal = Number(signal);
+}
+
+WifiNetwork.prototype.QueryInterface = XPCOMUtils.generateQI([Ci.nsIWifiNetwork]);
+
 function nsWifiWorker() {
   WifiManager.onsupplicantconnection = function() {
     debug("Connected to supplicant");
     WifiManager.getMacAddress(function (mac) {
       debug("Got mac: " + mac);
     });
   }
   WifiManager.onsupplicantlost = function() {
     debug("Couldn't connect to supplicant");
   }
 
-  var state;
+  var self = this;
+
+  this.state = null;
+  this.networks = Object.create(null);
   WifiManager.onstatechange = function() {
-    debug("State change: " + state + " -> " + this.state);
-    if (state === "SCANNING" && this.state === "INACTIVE") {
-      // We're not trying to connect so try to find an open Mozilla network.
-      // TODO Remove me in favor of UI and a way to select a network.
+    debug("State change: " + self.state + " -> " + this.state);
+    self.state = this.state;
+
+    // TODO Worth adding a more generic API for this?
+    if (self.state === "INACTIVE" && connectToMozilla.waiting)
+      connectToMozilla();
+  }
+
+  function connectToMozilla() {
+    if (self.state !== "INACTIVE") {
+      connectToMozilla.waiting = true;
+      return;
+    }
+
+    // We're not trying to connect so try to find an open Mozilla network.
+    // TODO Remove me in favor of UI and a way to select a network.
 
-      debug("Haven't connected to a network, trying a default (for now)");
-      var name = "Mozilla";
-      var net = networks[name];
-      if (net && (net[1] && net[1] !== "[IBSS]")) {
-        debug("Network Mozilla exists, but is encrypted");
-        net = null;
+    debug("Haven't connected to a network, trying a default (for now)");
+    var name = "Mozilla";
+    var net = self.networks[name];
+    if (net && (net.flags && net.flags !== "[IBSS]")) {
+      debug("Network Mozilla exists, but is encrypted");
+      net = null;
+    }
+
+    var config = Object.create(null);
+    if (!net) {
+      name = "Mozilla Guest";
+      net = self.networks[name];
+      if (!net || (net.flags && net.flags !== "[IBSS]")) {
+        debug("Can't find either network, trying to force 'Mozilla Guest'");
+        config.scan_ssid = 1;
       }
-      if (!net) {
-        name = "Mozilla Guest";
-        net = networks[name];
-        if (!net || (net[1] && net[1] !== "[IBSS]")) {
-          debug("Network Mozilla Guest doesn't exist or is encrypted");
-          return;
-        }
+    }
+
+    config.ssid = '"' + name + '"';
+    config.key_mgmt = "NONE";
+    WifiManager.addNetwork(config, function(ok) {
+      if (!ok) {
+        debug("Unable to add the network!");
+        return;
       }
 
-      var config = Object.create(null);
-      config["ssid"] = '"' + name + '"';
-      config["key_mgmt"] = "NONE";
-      WifiManager.addNetwork(config, function(ok) {
-        if (!ok) {
-          debug("Unable to add the network!");
-          return;
-        }
+      WifiManager.enableNetwork(config.netId, false, function(ok) {
+        debug((ok ? "Successfully enabled " : "Didn't enable ") + name);
+      });
+    });
+  }
+  this.waitForScan(connectToMozilla);
 
-        WifiManager.enableNetwork(config.netId, false, function(ok) {
-          debug((ok ? "Successfully enabled " : "Didn't enable ") + name);
-        });
-      });
-    }
-
-    state = this.state;
-  }
-
-  var networks = Object.create(null);
   WifiManager.onscanresultsavailable = function() {
     debug("Scan results are available! Asking for them.");
     WifiManager.getScanResults(function(r) {
       let lines = r.split("\n");
       // NB: Skip the header line.
       for (let i = 1; i < lines.length; ++i) {
         // bssid / frequency / signal level / flags / ssid
-        var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s+(.*)/.exec(lines[i])
-        if (match)
-          networks[match[5]] = [match[1], match[4]];
-        else
+        var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s+(.*)/.exec(lines[i]);
+
+        // TODO Choose bssid based on strength?
+        if (match && match[5])
+          self.networks[match[5]] = new WifiNetwork(match[5], match[1], match[4], match[3]);
+        else if (!match)
           debug("Match didn't find anything for: " + lines[i]);
       }
+
+      if (self.wantScanResults) {
+        self.wantScanResults();
+      }
     });
   }
 
   WifiManager.setWifiEnabled(true, function (ok) {
       if (ok === 0)
         WifiManager.start();
       else
         debug("Couldn't start Wifi");
@@ -880,16 +908,28 @@ nsWifiWorker.prototype = {
                                     contractID: WIFIWORKER_CONTRACTID,
                                     classDescription: "WifiWorker",
                                     interfaces: [Ci.nsIWorkerHolder,
                                                  Ci.nsIWifi]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder,
                                          Ci.nsIWifi]),
 
+  // Internal methods.
+  waitForScan: function(callback) {
+    if (this.wantScanResults) {
+      var older = this.wantScanResults;
+      this.wantScanResults = function() { callback(); older(); };
+    } else {
+      this.wantScanResults = callback;
+    }
+  },
+
+  // nsIWifi
+
   setWifiEnabled: function(enable) {
     WifiManager.setWifiEnabled(enable, function (ok) {
       debug(ok);
     });
   },
 
   // This is a bit ugly, but works. In particular, this depends on the fact
   // that RadioManager never actually tries to get the worker from us.
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -166,24 +166,24 @@ private:
     }
 
     *aVp = STRING_TO_JSVAL(jsType);
 
     return true;
   }
 
   static JSBool
-  MozSlice(JSContext* aCx, uintN aArgc, jsval* aVp)
+  Slice(JSContext* aCx, uintN aArgc, jsval* aVp)
   {
     JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
     if (!obj) {
       return false;
     }
 
-    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "mozSlice");
+    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "slice");
     if (!blob) {
       return false;
     }
 
     jsdouble start = 0, end = 0;
     JSString* jsContentType = JS_GetEmptyString(JS_GetRuntime(aCx));
     if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "/IIS", &start,
                              &end, &jsContentType)) {
@@ -192,20 +192,20 @@ private:
 
     nsDependentJSString contentType;
     if (!contentType.init(aCx, jsContentType)) {
       return false;
     }
 
     PRUint8 optionalArgc = aArgc;
     nsCOMPtr<nsIDOMBlob> rtnBlob;
-    if (NS_FAILED(blob->MozSlice(static_cast<PRUint64>(start),
-                                 static_cast<PRUint64>(end),
-                                 contentType, optionalArgc,
-                                 getter_AddRefs(rtnBlob)))) {
+    if (NS_FAILED(blob->Slice(static_cast<PRUint64>(start),
+                              static_cast<PRUint64>(end),
+                              contentType, optionalArgc,
+                              getter_AddRefs(rtnBlob)))) {
       ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
       return false;
     }
 
     JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
     if (!rtnObj) {
       return false;
     }
@@ -225,17 +225,17 @@ JSClass Blob::sClass = {
 
 JSPropertySpec Blob::sProperties[] = {
   { "size", 0, PROPERTY_FLAGS, GetSize, js_GetterOnlyPropertyStub },
   { "type", 0, PROPERTY_FLAGS, GetType, js_GetterOnlyPropertyStub },
   { 0, 0, 0, NULL, NULL }
 };
 
 JSFunctionSpec Blob::sFunctions[] = {
-  JS_FN("mozSlice", MozSlice, 1, JSPROP_ENUMERATE),
+  JS_FN("slice", Slice, 1, JSPROP_ENUMERATE),
   JS_FS_END
 };
 
 class File : public Blob
 {
   // File should never be instantiated.
   File();
   ~File();
--- a/dom/workers/ListenerManager.cpp
+++ b/dom/workers/ListenerManager.cpp
@@ -102,16 +102,19 @@ struct Listener : PRCList
     listener->mPhase = aPhase;
     listener->mWantsUntrusted = aWantsUntrusted;
     return listener;
   }
 
   static void
   Remove(JSContext* aCx, Listener* aListener)
   {
+    if (js::IsIncrementalBarrierNeeded(aCx))
+      js::IncrementalValueBarrier(aListener->mListenerVal);
+
     PR_REMOVE_LINK(aListener);
     JS_free(aCx, aListener);
   }
 
   jsval mListenerVal;
   ListenerManager::Phase mPhase;
   bool mWantsUntrusted;
 };
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -295,17 +295,17 @@ private:
     }
 
     return worker->PostMessage(aCx, message);
   }
 };
 
 JSClass Worker::sClass = {
   "Worker",
-  JSCLASS_HAS_PRIVATE,
+  JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, NULL, NULL, NULL,
   NULL, NULL, NULL, Trace, NULL
 };
 
 JSPropertySpec Worker::sProperties[] = {
   { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
     GetEventListener, SetEventListener },
@@ -410,17 +410,17 @@ private:
     if (worker) {
       worker->TraceInstance(aTrc);
     }
   }
 };
 
 JSClass ChromeWorker::sClass = {
   "ChromeWorker",
-  JSCLASS_HAS_PRIVATE,
+  JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, NULL, NULL, NULL,
   NULL, NULL, NULL, Trace, NULL
 };
 
 WorkerPrivate*
 Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
                            const char* aFunctionName)
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -794,17 +794,17 @@ private:
     }
 
     return scope->mWorker->PostMessageToParent(aCx, message);
   }
 };
 
 JSClass DedicatedWorkerGlobalScope::sClass = {
   "DedicatedWorkerGlobalScope",
-  JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
+  JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE,
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   JS_EnumerateStub, reinterpret_cast<JSResolveOp>(Resolve), JS_ConvertStub,
   Finalize, NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
 };
 
 JSPropertySpec DedicatedWorkerGlobalScope::sProperties[] = {
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     GetEventListener, SetEventListener },
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -215,17 +215,17 @@ private:
     }
 
     return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
   }
 };
 
 JSClass XMLHttpRequestUpload::sClass = {
   "XMLHttpRequestUpload",
-  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
+  JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
   NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
 };
 
 JSPropertySpec XMLHttpRequestUpload::sProperties[] = {
   { sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
     GetEventListener, SetEventListener },
@@ -764,17 +764,17 @@ private:
     }
 
     return priv->OverrideMimeType(aCx, mimeType);
   }
 };
 
 JSClass XMLHttpRequest::sClass = {
   "XMLHttpRequest",
-  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
+  JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
   NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
 };
 
 JSPropertySpec XMLHttpRequest::sProperties[] = {
 
 #define GENERIC_READONLY_PROPERTY(_name) \
--- a/dom/workers/test/Makefile.in
+++ b/dom/workers/test/Makefile.in
@@ -131,31 +131,31 @@ include $(topsrcdir)/config/rules.mk
   $(NULL)
 
 _CHROME_TEST_FILES = \
   test_chromeWorker.xul \
   test_chromeWorkerJSM.xul \
   test_extension.xul \
   test_extensionBootstrap.xul \
   test_file.xul \
-  test_fileMozSlice.xul \
+  test_fileSlice.xul \
   test_fileBlobPosting.xul \
   test_filePosting.xul \
   test_fileReaderSync.xul \
   test_fileReaderSyncErrors.xul \
-  test_fileReadMozSlice.xul \
+  test_fileReadSlice.xul \
   test_fileSubWorker.xul \
   test_fileBlobSubWorker.xul \
   file_worker.js \
   fileBlob_worker.js \
-  fileMozSlice_worker.js \
+  fileSlice_worker.js \
   filePosting_worker.js \
   fileReaderSync_worker.js \
   fileReaderSyncErrors_worker.js \
-  fileReadMozSlice_worker.js \
+  fileReadSlice_worker.js \
   fileSubWorker_worker.js \
   fileBlobSubWorker_worker.js \
   WorkerTest.jsm \
   WorkerTest_worker.js \
   WorkerTest_subworker.js \
   chromeWorker_worker.js \
   chromeWorker_subworker.js \
   test_workersDisabled.xul \
rename from dom/workers/test/fileReadMozSlice_worker.js
rename to dom/workers/test/fileReadSlice_worker.js
--- a/dom/workers/test/fileReadMozSlice_worker.js
+++ b/dom/workers/test/fileReadSlice_worker.js
@@ -2,15 +2,15 @@
  * Expects an object containing a blob, a start index and an end index
  * for slicing. Returns the contents of the blob read as text.
  */
 onmessage = function(event) {
   var blob = event.data.blob;
   var start = event.data.start;
   var end = event.data.end;
 
-  var slicedBlob = blob.mozSlice(start, end);
+  var slicedBlob = blob.slice(start, end);
 
   var fileReader = new FileReaderSync();
   var text = fileReader.readAsText(slicedBlob);
 
   postMessage(text);
 };
rename from dom/workers/test/fileMozSlice_worker.js
rename to dom/workers/test/fileSlice_worker.js
--- a/dom/workers/test/fileMozSlice_worker.js
+++ b/dom/workers/test/fileSlice_worker.js
@@ -6,21 +6,21 @@
 onmessage = function(event) {
   var blob = event.data.blob;
   var start = event.data.start;
   var end = event.data.end;
   var contentType = event.data.contentType;
 
   var slicedBlob;
   if (contentType == undefined && end == undefined) {
-    slicedBlob = blob.mozSlice(start);
+    slicedBlob = blob.slice(start);
   } else if (contentType == undefined) {
-    slicedBlob = blob.mozSlice(start, end);
+    slicedBlob = blob.slice(start, end);
   } else {
-    slicedBlob = blob.mozSlice(start, end, contentType);
+    slicedBlob = blob.slice(start, end, contentType);
   }
 
   var rtnObj = new Object();
 
   rtnObj.size = slicedBlob.size;
   rtnObj.type = slicedBlob.type;
 
   postMessage(rtnObj);
--- a/dom/workers/test/test_fileBlobPosting.xul
+++ b/dom/workers/test/test_fileBlobPosting.xul
@@ -65,17 +65,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     };
 
     worker.onmessage = function(event) {
       console.log(event.data);
       is(event.data.size, file.size, "size of file posted from worker does not match file posted to worker.");
       finish();
     };
 
-    var blob = file.mozSlice();
+    var blob = file.slice();
     worker.postMessage(blob);
     waitForWorkerFinish();
   }
 
   // Empty file.
   postBlob(createFileWithData(""));
 
   // Typical use case.
--- a/dom/workers/test/test_fileBlobSubWorker.xul
+++ b/dom/workers/test/test_fileBlobSubWorker.xul
@@ -67,17 +67,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       if (event.data == undefined) {
         ok(false, "Worker had an error.");
       } else {
         is(event.data.size, expectedSize, "size proproperty accessed from worker is not the same as on main thread.");
       }
       finish();
     };
 
-    var blob = file.mozSlice();
+    var blob = file.slice();
     worker.postMessage(blob);
     waitForWorkerFinish();
   }
 
   // Empty file.
   accessFileProperties(createFileWithData(""), 0);
 
   // Typical use case.
rename from dom/workers/test/test_fileReadMozSlice.xul
rename to dom/workers/test/test_fileReadSlice.xul
--- a/dom/workers/test/test_fileReadMozSlice.xul
+++ b/dom/workers/test/test_fileReadSlice.xul
@@ -31,17 +31,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   /**
    * Create a file which contains the given data.
    */
   function createFileWithData(fileData) {
     var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
                        .getService(Components.interfaces.nsIProperties)
                        .get("ProfD", Components.interfaces.nsIFile);
-    testFile.append("workerReadMozSlice" + fileNum++);
+    testFile.append("workerReadSlice" + fileNum++);
 
     var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
                         .createInstance(Components.interfaces.nsIFileOutputStream);
     outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
                    0666, 0);
     outStream.write(fileData, fileData.length);
     outStream.close();
 
@@ -50,18 +50,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     return fileList.files[0];
   }
 
   /**
    * Creates a worker which slices a blob to the given start and end offset and
    * reads the content as text.
    */
-  function readMozSlice(blob, start, end, expectedText) {
-    var worker = new Worker("fileReadMozSlice_worker.js");
+  function readSlice(blob, start, end, expectedText) {
+    var worker = new Worker("fileReadSlice_worker.js");
 
     worker.onerror = function(event) {
       ok(false, "Worker had an error: " + event.data);
       finish();
     };
 
     worker.onmessage = function(event) {
       is(event.data, expectedText, "Text from sliced blob in worker is incorrect.");
@@ -69,22 +69,22 @@ https://bugzilla.mozilla.org/show_bug.cg
     };
 
     var params = {blob: blob, start: start, end: end};
     worker.postMessage(params);
     waitForWorkerFinish();
   }
 
   // Empty file.
-  readMozSlice(createFileWithData(""), 0, 0, "");
+  readSlice(createFileWithData(""), 0, 0, "");
 
   // Typical use case.
-  readMozSlice(createFileWithData("HelloBye"), 5, 8, "Bye");
+  readSlice(createFileWithData("HelloBye"), 5, 8, "Bye");
 
   // End offset too large.
-  readMozSlice(createFileWithData("HelloBye"), 5, 9, "Bye");
+  readSlice(createFileWithData("HelloBye"), 5, 9, "Bye");
 
   // Start of file.
-  readMozSlice(createFileWithData("HelloBye"), 0, 5, "Hello");
+  readSlice(createFileWithData("HelloBye"), 0, 5, "Hello");
 
   ]]>
   </script>
 </window>
rename from dom/workers/test/test_fileMozSlice.xul
rename to dom/workers/test/test_fileSlice.xul
--- a/dom/workers/test/test_fileMozSlice.xul
+++ b/dom/workers/test/test_fileSlice.xul
@@ -32,17 +32,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   /**
    * Create a file which contains the given data and optionally adds the specified file extension.
    */
   function createFileWithData(fileData, /** optional */ extension) {
     var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
                        .getService(Components.interfaces.nsIProperties)
                        .get("ProfD", Components.interfaces.nsIFile);
     var fileExtension = (extension == undefined) ? "" : "." + extension;
-    testFile.append("workerMozSlice" + fileNum++ + fileExtension);
+    testFile.append("workerSlice" + fileNum++ + fileExtension);
 
     var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
                         .createInstance(Components.interfaces.nsIFileOutputStream);
     outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
                    0666, 0);
     outStream.write(fileData, fileData.length);
     outStream.close();
 
@@ -51,18 +51,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     return fileList.files[0];
   }
 
   /**
    * Starts a worker which slices the blob to the given start offset and optional end offset and
    * content type. It then verifies that the size and type of the sliced blob is correct.
    */
-  function createMozSlice(blob, start, expectedLength, /** optional */ end, /** optional */ contentType) {
-    var worker = new Worker("fileMozSlice_worker.js");
+  function createSlice(blob, start, expectedLength, /** optional */ end, /** optional */ contentType) {
+    var worker = new Worker("fileSlice_worker.js");
 
     worker.onerror = function(event) {
       ok(false, "Worker had an error: " + event.data);
       finish();
     };
 
     worker.onmessage = function(event) {
       is(event.data.size, expectedLength, "size property of slice is incorrect.");
@@ -71,36 +71,36 @@ https://bugzilla.mozilla.org/show_bug.cg
     };
 
     var params = {blob: blob, start: start, end: end, contentType: contentType};
     worker.postMessage(params);
     waitForWorkerFinish();
   }
 
   // Empty file.
-  createMozSlice(createFileWithData(""), 0, 0, 0);
+  createSlice(createFileWithData(""), 0, 0, 0);
 
   // Typical use case.
-  createMozSlice(createFileWithData("Hello"), 1, 1, 2);
+  createSlice(createFileWithData("Hello"), 1, 1, 2);
 
   // Longish file.
   var text = "";
   for (var i = 0; i < 10000; ++i) {
     text += "long";
   }
-  createMozSlice(createFileWithData(text), 2000, 2000, 4000);
+  createSlice(createFileWithData(text), 2000, 2000, 4000);
 
   // Slice to different type.
-  createMozSlice(createFileWithData("text", "txt"), 0, 2, 2, "image/png");
+  createSlice(createFileWithData("text", "txt"), 0, 2, 2, "image/png");
 
   // Length longer than blob.
-  createMozSlice(createFileWithData("text"), 0, 4, 20);
+  createSlice(createFileWithData("text"), 0, 4, 20);
 
   // Start longer than blob.
-  createMozSlice(createFileWithData("text"), 20, 0, 4);
+  createSlice(createFileWithData("text"), 20, 0, 4);
 
   // No optional arguments
-  createMozSlice(createFileWithData("text"), 0, 4);
-  createMozSlice(createFileWithData("text"), 2, 2);
+  createSlice(createFileWithData("text"), 0, 4);
+  createSlice(createFileWithData("text"), 2, 2);
 
   ]]>
   </script>
 </window>
--- a/editor/composer/src/nsEditorSpellCheck.cpp
+++ b/editor/composer/src/nsEditorSpellCheck.cpp
@@ -78,17 +78,17 @@ class UpdateDictionnaryHolder {
       if (mSpellCheck) {
         mSpellCheck->EndUpdateDictionary();
       }
     }
 };
 
 #define CPS_PREF_NAME NS_LITERAL_STRING("spellcheck.lang")
 
-class LastDictionary {
+class LastDictionary MOZ_FINAL {
 public:
   /**
    * Store current dictionary for editor document url. Use content pref
    * service.
    */
   NS_IMETHOD StoreCurrentDictionary(nsIEditor* aEditor, const nsAString& aDictionary);
 
   /**
--- a/editor/idl/nsIEditor.idl
+++ b/editor/idl/nsIEditor.idl
@@ -50,17 +50,17 @@ interface nsIDocumentStateListener;
 interface nsIOutputStream;
 interface nsITransactionManager;
 interface nsITransaction;
 interface nsIEditorObserver;
 interface nsIEditActionListener;
 interface nsIInlineSpellChecker;
 interface nsITransferable;
 
-[scriptable, uuid(20ee0b70-c528-11e0-9572-0800200c9a66)]
+[scriptable, uuid(94479B76-7FD7-47D3-BB1E-5B77846339D2)]
 
 interface nsIEditor  : nsISupports
 {
 %{C++
   typedef short EDirection;
 %}
   const short eNone = 0;
   const short eNext = 1;
@@ -355,36 +355,16 @@ interface nsIEditor  : nsISupports
   void selectAll();
 
   /** sets the document selection to the beginning of the document */
   void beginningOfDocument();
 
   /** sets the document selection to the end of the document */
   void endOfDocument();
 
-   /* ------------ Drag/Drop methods -------------- */
-  
-   /** 
-    * canDrag decides if a drag should be started
-    * (for example, based on the current selection and mousepoint).
-    */
-  boolean canDrag(in nsIDOMEvent aEvent);
- 
-   /** 
-    * doDrag transfers the relevant data (as appropriate)
-    * to a transferable so it can later be dropped.
-    */
-  void doDrag(in nsIDOMEvent aEvent);
- 
-   /** 
-    * insertFromDrop looks for a dragsession and inserts the
-    * relevant data in response to a drop.
-    */
-  void insertFromDrop(in nsIDOMEvent aEvent);
-
   /* ------------ Node manipulation methods -------------- */
 
   /**
    * setAttribute() sets the attribute of aElement.
    * No checking is done to see if aAttribute is a legal attribute of the node,
    * or if aValue is a legal value of aAttribute.
    *
    * @param aElement    the content element to operate on
--- a/editor/idl/nsIHTMLEditor.idl
+++ b/editor/idl/nsIHTMLEditor.idl
@@ -47,17 +47,17 @@ interface nsISupportsArray;
 interface nsISelection;
 interface nsIContentFilter;
 
 %{C++
 #define NS_EDITOR_ELEMENT_NOT_FOUND \
   NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_EDITOR, 1)
 
 %}
-[scriptable, uuid(d58f35a7-c269-4292-b9aa-a79e200a7c99)]
+[scriptable, uuid(FF67AD39-ED58-4CD1-A1A3-DCD988390A97)]
 
 interface nsIHTMLEditor : nsISupports
 {
 %{C++
   typedef short EAlignment;
 %}
 
   // used by GetAlignment()
@@ -194,36 +194,16 @@ interface nsIHTMLEditor : nsISupports
 
   /**
    *  Decrease font size for text in selection by 1 HTML unit
    *  All existing text is scanned for existing <FONT SIZE> attributes
    *  so they will be decreased instead of inserting new <FONT> tag
    */
   void decreaseFontSize();
 
-  /* ------------ Drag/Drop methods -------------- */
-
-  /** 
-   * canDrag decides if a drag should be started
-   * (for example, based on the current selection and mousepoint).
-   */
-  boolean canDrag(in nsIDOMEvent aEvent);
-
-  /** 
-   * doDrag transfers the relevant data (as appropriate)
-   * to a transferable so it can later be dropped.
-   */
-  void doDrag(in nsIDOMEvent aEvent);
-
-  /** 
-   * insertFromDrop looks for a dragsession and inserts the
-   * relevant data in response to a drop.
-   */
-  void insertFromDrop(in nsIDOMEvent aEvent);
-
   /* ------------ HTML content methods -------------- */
 
   /**
    * Tests if a node is a BLOCK element according the the HTML 4.0 DTD.
    *   This does NOT consider CSS effect on display type
    *
    * @param aNode      the node to test
    */
@@ -529,22 +509,16 @@ interface nsIHTMLEditor : nsISupports
    *
    * 8/31/00 THIS ISN'T BEING USED? SHOULD WE DROP IT?
    *
    * @param aAttr   The attribute to be set
    * @param aValue  The value of the attribute
    */
   void setBodyAttribute(in AString aAttr, in AString aValue);
   
-  /** 
-   * XXX Used to suppress spurious drag/drop events to workaround bug 50703
-   * Don't use this method! It will go away after first release!
-   */
-  void ignoreSpuriousDragEvent(in boolean aIgnoreSpuriousDragEvent);
-
   /**
    * Find all the nodes in the document which contain references
    * to outside URIs (e.g. a href, img src, script src, etc.)
    * The objects in the array will be type nsIURIRefObject.
    *
    * @return aNodeList    the linked nodes found
    */
   nsISupportsArray getLinkedObjects();
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -1186,35 +1186,16 @@ nsEditor::CanPaste(PRInt32 aSelectionTyp
 }
 
 NS_IMETHODIMP
 nsEditor::CanPasteTransferable(nsITransferable *aTransferable, bool *aCanPaste)
 {
   return NS_ERROR_NOT_IMPLEMENTED; 
 }
 
-NS_IMETHODIMP
-nsEditor::CanDrag(nsIDOMEvent *aEvent, bool *aCanDrag)
-{
-  return NS_ERROR_NOT_IMPLEMENTED; 
-}
-
-NS_IMETHODIMP
-nsEditor::DoDrag(nsIDOMEvent *aEvent)
-{
-  return NS_ERROR_NOT_IMPLEMENTED; 
-}
-
-NS_IMETHODIMP
-nsEditor::InsertFromDrop(nsIDOMEvent *aEvent)
-{
-  return NS_ERROR_NOT_IMPLEMENTED; 
-}
-
-
 NS_IMETHODIMP 
 nsEditor::SetAttribute(nsIDOMElement *aElement, const nsAString & aAttribute, const nsAString & aValue)
 {
   nsRefPtr<ChangeAttributeTxn> txn;
   nsresult result = CreateTxnForSetAttribute(aElement, aAttribute, aValue,
                                              getter_AddRefs(txn));
   if (NS_SUCCEEDED(result))  {
     result = DoTransaction(txn);  
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -752,16 +752,30 @@ public:
   // nothing.
   nsresult InitializeSelection(nsIDOMEventTarget* aFocusEventTarget);
 
   // This method has to be called by nsEditorEventListener::Focus.
   // All actions that have to be done when the editor is focused needs to be
   // added here.
   void OnFocus(nsIDOMEventTarget* aFocusEventTarget);
 
+  // Used to insert content from a data transfer into the editable area.
+  // This is called for each item in the data transfer, with the index of
+  // each item passed as aIndex.
+  virtual nsresult InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
+                                          PRInt32 aIndex,
+                                          nsIDOMDocument *aSourceDoc,
+                                          nsIDOMNode *aDestinationNode,
+                                          PRInt32 aDestOffset,
+                                          bool aDoDeleteSelection) = 0;
+
+  virtual nsresult InsertFromDrop(nsIDOMEvent* aDropEvent) = 0;
+
+  virtual already_AddRefed<nsIDOMNode> FindUserSelectAllNode(nsIDOMNode* aNode) { return nsnull; }
+
 protected:
 
   PRUint32        mModCount;     // number of modifications (for undo/redo stack)
   PRUint32        mFlags;        // behavior flags. See nsIPlaintextEditor.idl for the flags we use.
 
   nsWeakPtr       mSelConWeak;   // weak reference to the nsISelectionController
   PRInt32         mUpdateCount;
 
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -56,18 +56,16 @@
 #include "nsFocusManager.h"
 #include "nsEventListenerManager.h"
 #include "nsIMEStateManager.h"
 #include "mozilla/Preferences.h"
 
 // Drag & Drop, Clipboard
 #include "nsIServiceManager.h"
 #include "nsIClipboard.h"
-#include "nsIDragService.h"
-#include "nsIDragSession.h"
 #include "nsIContent.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMRange.h"
 #include "nsEditorUtils.h"
 #include "nsISelectionPrivate.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIFocusManager.h"
 #include "nsIDOMWindow.h"
@@ -153,21 +151,16 @@ nsEditorEventListener::InstallToEditor()
                                NS_LITERAL_STRING("keyup"),
                                NS_EVENT_FLAG_BUBBLE |
                                NS_EVENT_FLAG_SYSTEM_EVENT);
 #endif
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("keypress"),
                                NS_EVENT_FLAG_BUBBLE |
                                NS_EVENT_FLAG_SYSTEM_EVENT);
-  // See bug 455215, we cannot use the standard dragstart event yet
-  elmP->AddEventListenerByType(this,
-                               NS_LITERAL_STRING("draggesture"),
-                               NS_EVENT_FLAG_BUBBLE |
-                               NS_EVENT_FLAG_SYSTEM_EVENT);
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("dragenter"),
                                NS_EVENT_FLAG_BUBBLE |
                                NS_EVENT_FLAG_SYSTEM_EVENT);
   elmP->AddEventListenerByType(this,
                                NS_LITERAL_STRING("dragover"),
                                NS_EVENT_FLAG_BUBBLE |
                                NS_EVENT_FLAG_SYSTEM_EVENT);
@@ -251,20 +244,16 @@ nsEditorEventListener::UninstallFromEdit
                                   NS_EVENT_FLAG_BUBBLE |
                                   NS_EVENT_FLAG_SYSTEM_EVENT);
 #endif
   elmP->RemoveEventListenerByType(this,
                                   NS_LITERAL_STRING("keypress"),
                                   NS_EVENT_FLAG_BUBBLE |
                                   NS_EVENT_FLAG_SYSTEM_EVENT);
   elmP->RemoveEventListenerByType(this,
-                                  NS_LITERAL_STRING("draggesture"),
-                                  NS_EVENT_FLAG_BUBBLE |
-                                  NS_EVENT_FLAG_SYSTEM_EVENT);
-  elmP->RemoveEventListenerByType(this,
                                   NS_LITERAL_STRING("dragenter"),
                                   NS_EVENT_FLAG_BUBBLE |
                                   NS_EVENT_FLAG_SYSTEM_EVENT);
   elmP->RemoveEventListenerByType(this,
                                   NS_LITERAL_STRING("dragover"),
                                   NS_EVENT_FLAG_BUBBLE |
                                   NS_EVENT_FLAG_SYSTEM_EVENT);
   elmP->RemoveEventListenerByType(this,
@@ -327,18 +316,16 @@ nsEditorEventListener::HandleEvent(nsIDO
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
 
   nsAutoString eventType;
   aEvent->GetType(eventType);
 
   nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
   if (dragEvent) {
-    if (eventType.EqualsLiteral("draggesture"))
-      return DragGesture(dragEvent);
     if (eventType.EqualsLiteral("dragenter"))
       return DragEnter(dragEvent);
     if (eventType.EqualsLiteral("dragover"))
       return DragOver(dragEvent);
     if (eventType.EqualsLiteral("dragexit"))
       return DragExit(dragEvent);
     if (eventType.EqualsLiteral("drop"))
       return Drop(dragEvent);
@@ -654,28 +641,16 @@ nsEditorEventListener::HandleText(nsIDOM
   return mEditor->UpdateIMEComposition(composedText, textRangeList);
 }
 
 /**
  * Drag event implementation
  */
 
 nsresult
-nsEditorEventListener::DragGesture(nsIDOMDragEvent* aDragEvent)
-{
-  // ...figure out if a drag should be started...
-  bool canDrag;
-  nsresult rv = mEditor->CanDrag(aDragEvent, &canDrag);
-  if ( NS_SUCCEEDED(rv) && canDrag )
-    rv = mEditor->DoDrag(aDragEvent);
-
-  return rv;
-}
-
-nsresult
 nsEditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
 {
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   NS_ENSURE_TRUE(presShell, NS_OK);
 
   if (!mCaret) {
     mCaret = new nsCaret();
     mCaret->Init(presShell);
@@ -718,16 +693,20 @@ nsEditorEventListener::DragOver(nsIDOMDr
         mCaret->EraseCaret();
       
       //mCaret->SetCaretVisible(true);   // make sure it's visible
       mCaret->DrawAtPosition(parent, offset);
     }
   }
   else
   {
+    // This is needed when dropping on an input, to prevent the editor for
+    // the editable parent from receiving the event.
+    aDragEvent->StopPropagation();
+
     if (mCaret)
     {
       mCaret->EraseCaret();
     }
   }
 
   return NS_OK;
 }
@@ -789,18 +768,16 @@ nsEditorEventListener::Drop(nsIDOMDragEv
       // editfields if that is what is desired.
       return aMouseEvent->StopPropagation();
     }
     return NS_OK;
   }
 
   aMouseEvent->StopPropagation();
   aMouseEvent->PreventDefault();
-  // Beware! This may flush notifications via synchronous
-  // ScrollSelectionIntoView.
   return mEditor->InsertFromDrop(aMouseEvent);
 }
 
 bool
 nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
 {
   // if the target doc is read-only, we can't drop
   if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
--- a/editor/libeditor/base/nsEditorUtils.h
+++ b/editor/libeditor/base/nsEditorUtils.h
@@ -252,17 +252,16 @@ struct NS_STACK_CLASS DOMPoint
 class nsEditorUtils
 {
   public:
     static bool IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 *aOffset = 0);
     static bool IsLeafNode(nsIDOMNode *aNode);
 };
 
 
-class nsIDragSession;
 class nsITransferable;
 class nsIDOMEvent;
 class nsISimpleEnumerator;
 
 class nsEditorHookUtils
 {
   public:
     static bool     DoInsertionHook(nsIDOMDocument *aDoc, nsIDOMEvent *aEvent,
--- a/editor/libeditor/base/tests/Makefile.in
+++ b/editor/libeditor/base/tests/Makefile.in
@@ -51,16 +51,17 @@ include $(topsrcdir)/config/rules.mk
 		file_bug586662.html \
 		test_bug586662.html \
 		$(NULL)
 
 _CHROME_TEST_FILES = \
 		test_selection_move_commands.xul \
                 test_bug46555.html \
 		test_bug646194.xul \
+		test_dragdrop.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_CHROME_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
 
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/base/tests/test_dragdrop.html
@@ -0,0 +1,163 @@
+<html>
+
+<head>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
+</head>
+
+<body>
+  <span id="text" style="font-size: 40px;">Some Text</span>
+
+  <input id="input" value="Drag Me">
+  <textarea id="textarea">Some Text To Drag</textarea>
+  <p id="contenteditable" contenteditable="true">This is some <b id="bold">editable</b> text.</p>
+
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+// This listener allows us to clear the default data for the selection added for the drag.
+var shouldClear = false;
+window.addEventListener("dragstart", function (event) { if (shouldClear) event.dataTransfer.clearData() }, true);
+
+function doTest()
+{
+  const htmlContextData = { type: 'text/_moz_htmlcontext',
+                            data: '<html><body></body></html>' };
+  const htmlInfoData = { type: 'text/_moz_htmlinfo', data: '0,0' };
+  const htmlData = { type: 'text/html', data: '<span id="text" style="font-size: 40px;">Some Text</span>' };
+
+  const htmlContextDataEditable = { type: 'text/_moz_htmlcontext',
+                                    data: '<html><body><p id="contenteditable" contenteditable="true"></p></body></html>' };
+
+  var text = document.getElementById("text");
+  var input = document.getElementById("input");
+  var contenteditable = document.getElementById("contenteditable");
+
+  var selection = window.getSelection();
+
+  // -------- Test dragging regular text
+  selection.selectAllChildren(text);
+  var result = synthesizeDragStart(text, [[htmlContextData, htmlInfoData, htmlData,
+                                           {type: "text/plain", data: "Some Text"}]], window, 40, 10);
+  ok(!result, "Test dragging regular text");
+
+  // -------- Test dragging text from an <input>
+  input.setSelectionRange(1, 4);
+  result = synthesizeDragStart(input, [[{type: "text/plain", data: "rag"}]], window, 25, 6);
+  ok(!result, "Test dragging input");
+
+  // -------- Test dragging text from a <textarea>
+  textarea.setSelectionRange(1, 7);
+  result = synthesizeDragStart(textarea, [[{type: "text/plain", data: "ome Te"}]], window, 25, 6);
+  ok(!result, "Test dragging textarea");
+  textarea.blur();
+
+  // -------- Test dragging text from a contenteditable
+  selection.selectAllChildren(contenteditable.childNodes[1]);
+  result = synthesizeDragStart(contenteditable.childNodes[1],
+                               [[htmlContextDataEditable, htmlInfoData,
+                                {type: 'text/html', data: '<b id="bold">editable</b>' },
+                                {type: "text/plain", data: "editable"}]], window, 5, 6);
+  ok(!result, "Test dragging contenteditable");
+  contenteditable.blur();
+
+  // -------- Test dragging regular text of text/html to <input>
+
+  selection.selectAllChildren(text);
+  input.value = "";
+  synthesizeDrop(text, input, [], "copy");
+  is(input.value, "Some Text", "Drag text/html onto input");
+
+  // -------- Test dragging regular text of text/html to disabled <input>
+
+  selection.selectAllChildren(text);
+  input.value = "";
+  input.disabled = true;
+  synthesizeDrop(text, input, [], "copy");
+  is(input.value, "", "Drag text/html onto disabled input");
+  input.disabled = false;
+
+  // -------- Test dragging regular text of text/html to readonly <input>
+
+  selection.selectAllChildren(text);
+  input.readOnly = true;
+  synthesizeDrop(text, input, [], "copy");
+  is(input.value, "", "Drag text/html onto readonly input");
+  input.readOnly = false;
+
+  // -------- Test dragging regular text of text/html to <input>. This sets
+  //          shouldClear to true so that the default drag data is not present
+  //          and we can use the data passed to synthesizeDrop. This allows
+  //          testing of a drop with just text/html.
+  shouldClear = true;
+  selection.selectAllChildren(text);
+  input.value = "";
+  synthesizeDrop(text, input, [[{type: "text/html", data: "Some <b>Bold<b> Text"}]], "copy");
+  is(input.value, "", "Drag text/html onto input");
+
+  // -------- Test dragging regular text of text/plain and text/html to <input>
+
+  selection.selectAllChildren(text);
+  input.value = "";
+  synthesizeDrop(text, input, [[{type: "text/html", data: "Some <b>Bold<b> Text"},
+                                {type: "text/plain", data: "Some Plain Text"}]], "copy");
+  is(input.value, "Some Plain Text", "Drag text/html and text/plain onto input");
+
+  // -------- Test dragging regular text of text/plain to <textarea>
+
+// XXXndeakin Can't test textareas due to some event handling issue
+//  selection.selectAllChildren(text);
+//  synthesizeDrop(text, textarea, [[{type: "text/plain", data: "Somewhat Longer Text"}]], "copy");
+//  is(textarea.value, "Somewhat Longer Text", "Drag text/plain onto textarea");
+
+  // -------- Test dragging regular text of text/plain to contenteditable
+
+  selection.selectAllChildren(text);
+  synthesizeDrop(text, contenteditable, [[{type: "text/plain", data: "Sample Text"}]], "copy");
+  is(contenteditable.childNodes.length, 3, "Drag text/plain onto contenteditable child nodes");
+  is(contenteditable.textContent, "This is some editable text.Sample Text",
+                                  "Drag text/plain onto contenteditable text");
+
+  // -------- Test dragging regular text of text/html to contenteditable
+
+  selection.selectAllChildren(text);
+  synthesizeDrop(text, contenteditable, [[{type: "text/html", data: "Sample <i>Italic</i> Text"}]], "copy");
+  is(contenteditable.childNodes.length, 6, "Drag text/html onto contenteditable child nodes");
+  is(contenteditable.childNodes[4].tagName, "I", "Drag text/html onto contenteditable italic");
+  is(contenteditable.childNodes[4].textContent, "Italic", "Drag text/html onto contenteditable italic text");
+
+  // -------- Test dragging contenteditable to <input>
+
+  selection.selectAllChildren(document.getElementById("bold"));
+  synthesizeDrop(bold, input, [[{type: "text/html", data: "<b>editable</b>"},
+                                {type: "text/plain", data: "editable"}]], "copy");
+  is(input.value, "Some Plain Texteditable", "Move text/html and text/plain from contenteditable onto input");
+
+  // -------- Test dragging contenteditable to contenteditable
+
+  shouldClear = false;
+
+  selection.selectAllChildren(contenteditable.childNodes[4]);
+  synthesizeDrop(contenteditable.childNodes[4], contenteditable, [], "copy");
+  is(contenteditable.childNodes.length, 7, "Move text/html and text/plain from contenteditable onto itself child nodes");
+  is(contenteditable.childNodes[6].tagName, "I", "Move text/html and text/plain from contenteditable onto itself italic");
+  is(contenteditable.childNodes[6].textContent, "Italic", "Move text/html and text/plain from contenteditable onto itself text");
+
+  // We'd test 'move' here as well as 'copy', but that requires knowledge of
+  // the source of the drag which drag simulation doesn't provide.
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForFocus(doTest);
+
+</script>
+</body>
+</html>
--- a/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
+++ b/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
@@ -97,17 +97,17 @@ static PRInt32 GetCSSFloatValue(nsIDOMCS
         f = 5;
       break;
     }
   }
 
   return (PRInt32) f;
 }
 
-class nsElementDeletionObserver : public nsIMutationObserver
+class nsElementDeletionObserver MOZ_FINAL : public nsIMutationObserver
 {
 public:
   nsElementDeletionObserver(nsINode* aNativeAnonNode, nsINode* aObservedNode)
   : mNativeAnonNode(aNativeAnonNode), mObservedNode(aObservedNode) {}
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMUTATIONOBSERVER
 protected:
   nsINode* mNativeAnonNode;
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -59,16 +59,18 @@
 
 #include "nsIDocumentObserver.h"
 #include "nsIDocumentStateListener.h"
 
 #include "nsIEnumerator.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMRange.h"
+#include "nsIDOMDOMStringList.h"
+#include "nsIDOMDragEvent.h"
 #include "nsCOMArray.h"
 #include "nsIFile.h"
 #include "nsIURL.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIPresShell.h"
@@ -126,19 +128,16 @@
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
 const PRUnichar nbsp = 160;
 
 static NS_DEFINE_CID(kCParserCID,     NS_PARSER_CID);
 
-// private clipboard data flavors for html copy/paste
-#define kHTMLContext   "text/_moz_htmlcontext"
-#define kHTMLInfo      "text/_moz_htmlinfo"
 #define kInsertCookie  "_moz_Insert Here_moz_"
 
 #define NS_FOUND_TARGET NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_EDITOR, 3)
 
 // some little helpers
 static bool FindIntegerAfterString(const char *aLeadingString, 
                                      nsCString &aCStr, PRInt32 &foundNumber);
 static nsresult RemoveFragComments(nsCString &theStr);
@@ -1199,16 +1198,126 @@ nsHTMLEditor::ParseCFHTML(nsCString & aC
                                                            nsLinebreakConverter::eLinebreakContent, 
                                                            oldLengthInChars, &newLengthInChars);
   // it's ok for context to be empty.  frag might be whole doc and contain all its context.
   
   // we're done!  
   return NS_OK;
 }
 
+bool nsHTMLEditor::IsSafeToInsertData(nsIDOMDocument* aSourceDoc)
+{
+  // Try to determine whether we should use a sanitizing fragment sink
+  bool isSafe = false;
+  nsCOMPtr<nsIDOMDocument> destdomdoc;
+  GetDocument(getter_AddRefs(destdomdoc));
+
+  nsCOMPtr<nsIDocument> destdoc = do_QueryInterface(destdomdoc);
+  NS_ASSERTION(destdoc, "Where is our destination doc?");
+  nsCOMPtr<nsISupports> container = destdoc->GetContainer();
+  nsCOMPtr<nsIDocShellTreeItem> dsti(do_QueryInterface(container));
+  nsCOMPtr<nsIDocShellTreeItem> root;
+  if (dsti)
+    dsti->GetRootTreeItem(getter_AddRefs(root));
+  nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
+  PRUint32 appType;
+  if (docShell && NS_SUCCEEDED(docShell->GetAppType(&appType)))
+    isSafe = appType == nsIDocShell::APP_TYPE_EDITOR;
+  if (!isSafe && aSourceDoc) {
+    nsCOMPtr<nsIDocument> srcdoc = do_QueryInterface(aSourceDoc);
+    NS_ASSERTION(srcdoc, "Where is our source doc?");
+
+    nsIPrincipal* srcPrincipal = srcdoc->NodePrincipal();
+    nsIPrincipal* destPrincipal = destdoc->NodePrincipal();
+    NS_ASSERTION(srcPrincipal && destPrincipal, "How come we don't have a principal?");
+    srcPrincipal->Subsumes(destPrincipal, &isSafe);
+  }
+
+  return isSafe;
+}
+
+nsresult nsHTMLEditor::InsertObject(const char* aType, nsISupports* aObject, bool aIsSafe,
+                                    nsIDOMDocument *aSourceDoc,
+                                    nsIDOMNode *aDestinationNode,
+                                    PRInt32 aDestOffset,
+                                    bool aDoDeleteSelection)
+{
+  nsresult rv;
+
+  const char* type = aType;
+
+  // Check to see if we can insert an image file
+  bool insertAsImage = false;
+  nsCOMPtr<nsIURI> fileURI;
+  if (0 == nsCRT::strcmp(type, kFileMime))
+  {
+    nsCOMPtr<nsIFile> fileObj(do_QueryInterface(aObject));
+    if (fileObj)
+    {
+      rv = NS_NewFileURI(getter_AddRefs(fileURI), fileObj);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
+      NS_ENSURE_TRUE(mime, NS_ERROR_FAILURE);
+      nsCAutoString contentType;
+      rv = mime->GetTypeFromFile(fileObj, contentType);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      // Accept any image type fed to us
+      if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"))) {
+        insertAsImage = true;
+        type = contentType.get();
+      }
+    }
+  }
+
+  if (0 == nsCRT::strcmp(type, kJPEGImageMime) ||
+      0 == nsCRT::strcmp(type, kPNGImageMime) ||
+      0 == nsCRT::strcmp(type, kGIFImageMime) ||
+      insertAsImage)
+  {
+    nsCOMPtr<nsIInputStream> imageStream;
+    if (insertAsImage) {
+      NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
+      rv = NS_OpenURI(getter_AddRefs(imageStream), fileURI);
+      NS_ENSURE_SUCCESS(rv, rv);
+    } else {
+      imageStream = do_QueryInterface(aObject);
+      NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
+    }
+
+    nsCString imageData;
+    rv = NS_ConsumeStream(imageStream, PR_UINT32_MAX, imageData);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = imageStream->Close();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    char * base64 = PL_Base64Encode(imageData.get(), imageData.Length(), nsnull);
+    NS_ENSURE_TRUE(base64, NS_ERROR_OUT_OF_MEMORY);
+
+    nsAutoString stuffToPaste;
+    stuffToPaste.AssignLiteral("<IMG src=\"data:");
+    AppendUTF8toUTF16(aType, stuffToPaste);
+    stuffToPaste.AppendLiteral(";base64,");
+    AppendUTF8toUTF16(base64, stuffToPaste);
+    stuffToPaste.AppendLiteral("\" alt=\"\" >");
+    nsAutoEditBatch beginBatching(this);
+    rv = DoInsertHTMLWithContext(stuffToPaste, EmptyString(), EmptyString(), 
+                                 NS_LITERAL_STRING(kFileMime),
+                                 aSourceDoc,
+                                 aDestinationNode, aDestOffset,
+                                 aDoDeleteSelection,
+                                 aIsSafe);
+    PR_Free(base64);
+  }
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable, 
                                                    nsIDOMDocument *aSourceDoc,
                                                    const nsAString & aContextStr,
                                                    const nsAString & aInfoStr,
                                                    nsIDOMNode *aDestinationNode,
                                                    PRInt32 aDestOffset,
                                                    bool aDoDeleteSelection)
 {
@@ -1221,69 +1330,26 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTr
     nsAutoTxnsConserveSelection dontSpazMySelection(this);
     nsAutoString flavor;
     flavor.AssignWithConversion(bestFlavor);
     nsAutoString stuffToPaste;
 #ifdef DEBUG_clipboard
     printf("Got flavor [%s]\n", bestFlavor.get());
 #endif
 
-    // Try to determine whether we should use a sanitizing fragment sink
-    bool isSafe = false;
-    nsCOMPtr<nsIDOMDocument> destdomdoc;
-    rv = GetDocument(getter_AddRefs(destdomdoc));
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsCOMPtr<nsIDocument> destdoc = do_QueryInterface(destdomdoc);
-    NS_ASSERTION(destdoc, "Where is our destination doc?");
-    nsCOMPtr<nsISupports> container = destdoc->GetContainer();
-    nsCOMPtr<nsIDocShellTreeItem> dsti(do_QueryInterface(container));
-    nsCOMPtr<nsIDocShellTreeItem> root;
-    if (dsti)
-      dsti->GetRootTreeItem(getter_AddRefs(root));
-    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
-    PRUint32 appType;
-    if (docShell && NS_SUCCEEDED(docShell->GetAppType(&appType)))
-      isSafe = appType == nsIDocShell::APP_TYPE_EDITOR;
-    if (!isSafe && aSourceDoc) {
-      nsCOMPtr<nsIDocument> srcdoc = do_QueryInterface(aSourceDoc);
-      NS_ASSERTION(srcdoc, "Where is our source doc?");
-
-      nsIPrincipal* srcPrincipal = srcdoc->NodePrincipal();
-      nsIPrincipal* destPrincipal = destdoc->NodePrincipal();
-      NS_ASSERTION(srcPrincipal && destPrincipal, "How come we don't have a principal?");
-      rv = srcPrincipal->Subsumes(destPrincipal, &isSafe);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
+    bool isSafe = IsSafeToInsertData(aSourceDoc);
 
-    // Check to see if we can insert an image file
-    bool insertAsImage = false;
-    nsCOMPtr<nsIURI> fileURI;
-    if (0 == nsCRT::strcmp(bestFlavor, kFileMime))
-    {
-      nsCOMPtr<nsIFile> fileObj(do_QueryInterface(genericDataObj));
-      if (fileObj && len > 0)
-      {
-        rv = NS_NewFileURI(getter_AddRefs(fileURI), fileObj);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
-        NS_ENSURE_TRUE(mime, NS_ERROR_FAILURE);
-        nsCAutoString contentType;
-        rv = mime->GetTypeFromFile(fileObj, contentType);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        // Accept any image type fed to us
-        if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"))) {
-          insertAsImage = true;
-          bestFlavor = contentType;
-        }
-      }
+  	if (0 == nsCRT::strcmp(bestFlavor, kFileMime) ||
+        0 == nsCRT::strcmp(bestFlavor, kJPEGImageMime) ||
+        0 == nsCRT::strcmp(bestFlavor, kPNGImageMime) ||
+        0 == nsCRT::strcmp(bestFlavor, kGIFImageMime)) {
+      rv = InsertObject(bestFlavor, genericDataObj, isSafe,
+                        aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
     }
-
-    if (0 == nsCRT::strcmp(bestFlavor, kNativeHTMLMime))
+    else if (0 == nsCRT::strcmp(bestFlavor, kNativeHTMLMime))
     {
       // note cf_html uses utf8, hence use length = len, not len/2 as in flavors below
       nsCOMPtr<nsISupportsCString> textDataObj(do_QueryInterface(genericDataObj));
       if (textDataObj && len > 0)
       {
         nsCAutoString cfhtml;
         textDataObj->GetData(cfhtml);
         NS_ASSERTION(cfhtml.Length() <= (len), "Invalid length!");
@@ -1297,438 +1363,155 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTr
                                        cfcontext, cfselection, flavor,
                                        aSourceDoc,
                                        aDestinationNode, aDestOffset,
                                        aDoDeleteSelection,
                                        isSafe);
         }
       }
     }
-    else if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime))
-    {
-      nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
-      if (textDataObj && len > 0)
-      {
-        nsAutoString text;
-        textDataObj->GetData(text);
-        NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
-        stuffToPaste.Assign(text.get(), len / 2);
-        nsAutoEditBatch beginBatching(this);
-        rv = DoInsertHTMLWithContext(stuffToPaste,
-                                     aContextStr, aInfoStr, flavor,
-                                     aSourceDoc,
-                                     aDestinationNode, aDestOffset,
-                                     aDoDeleteSelection,
-                                     isSafe);
-      }
-    }
-    else if (0 == nsCRT::strcmp(bestFlavor, kUnicodeMime) ||
-             0 == nsCRT::strcmp(bestFlavor, kMozTextInternal))
-    {
+    else if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime) ||
+             0 == nsCRT::strcmp(bestFlavor, kUnicodeMime) ||
+             0 == nsCRT::strcmp(bestFlavor, kMozTextInternal)) {
       nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
       if (textDataObj && len > 0)
       {
         nsAutoString text;
         textDataObj->GetData(text);
         NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
         stuffToPaste.Assign(text.get(), len / 2);
+
         nsAutoEditBatch beginBatching(this);
-        // need to provide a hook from this point
-        rv = InsertTextAt(stuffToPaste, aDestinationNode, aDestOffset, aDoDeleteSelection);
+        if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime)) {
+          rv = DoInsertHTMLWithContext(stuffToPaste,
+                                       aContextStr, aInfoStr, flavor,
+                                       aSourceDoc,
+                                       aDestinationNode, aDestOffset,
+                                       aDoDeleteSelection,
+                                       isSafe);
+        } else {
+          rv = InsertTextAt(stuffToPaste, aDestinationNode, aDestOffset, aDoDeleteSelection);
+        }
       }
     }
-    else if (0 == nsCRT::strcmp(bestFlavor, kJPEGImageMime) ||
-             0 == nsCRT::strcmp(bestFlavor, kPNGImageMime) ||
-             0 == nsCRT::strcmp(bestFlavor, kGIFImageMime) ||
-             insertAsImage)
-    {
-      nsCOMPtr<nsIInputStream> imageStream;
-      if (insertAsImage) {
-        NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
-        rv = NS_OpenURI(getter_AddRefs(imageStream), fileURI);
-        NS_ENSURE_SUCCESS(rv, rv);
-      } else {
-        imageStream = do_QueryInterface(genericDataObj);
-        NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
-      }
-
-      nsCString imageData;
-      rv = NS_ConsumeStream(imageStream, PR_UINT32_MAX, imageData);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = imageStream->Close();
-      NS_ENSURE_SUCCESS(rv, rv);
+  }
 
-      char * base64 = PL_Base64Encode(imageData.get(), imageData.Length(), nsnull);
-      NS_ENSURE_TRUE(base64, NS_ERROR_OUT_OF_MEMORY);
-
-      stuffToPaste.AssignLiteral("<IMG src=\"data:");
-      AppendUTF8toUTF16(bestFlavor, stuffToPaste);
-      stuffToPaste.AppendLiteral(";base64,");
-      AppendUTF8toUTF16(base64, stuffToPaste);
-      stuffToPaste.AppendLiteral("\" alt=\"\" >");
-      nsAutoEditBatch beginBatching(this);
-      rv = DoInsertHTMLWithContext(stuffToPaste, EmptyString(), EmptyString(), 
-                                   NS_LITERAL_STRING(kFileMime),
-                                   aSourceDoc,
-                                   aDestinationNode, aDestOffset,
-                                   aDoDeleteSelection,
-                                   isSafe);
-      PR_Free(base64);
-    }
-  }
-      
-  // Try to scroll the selection into view if the paste/drop succeeded
-
-  // After ScrollSelectionIntoView(), the pending notifications might be
-  // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
+  // Try to scroll the selection into view if the paste succeeded
   if (NS_SUCCEEDED(rv))
     ScrollSelectionIntoView(false);
 
   return rv;
 }
 
-NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
+static void
+GetStringFromDataTransfer(nsIDOMDataTransfer *aDataTransfer, const nsAString& aType,
+                          PRInt32 aIndex, nsAString& aOutputString)
 {
-  ForceCompositionEnd();
-  
-  nsresult rv;
-  nsCOMPtr<nsIDragService> dragService = 
-           do_GetService("@mozilla.org/widget/dragservice;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDragSession> dragSession;
-  dragService->GetCurrentSession(getter_AddRefs(dragSession)); 
-  NS_ENSURE_TRUE(dragSession, NS_OK);
-
-  // transferable hooks here
-  nsCOMPtr<nsIDOMDocument> domdoc;
-  GetDocument(getter_AddRefs(domdoc));
+  nsCOMPtr<nsIVariant> variant;
+  aDataTransfer->MozGetDataAt(aType, aIndex, getter_AddRefs(variant));
+  if (variant)
+    variant->GetAsAString(aOutputString);
+}
 
-  // find out if we have our internal html flavor on the clipboard.  We don't want to mess
-  // around with cfhtml if we do.
-  bool bHavePrivateHTMLFlavor = false;
-  rv = dragSession->IsDataFlavorSupported(kHTMLContext, &bHavePrivateHTMLFlavor);
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  // Get the nsITransferable interface for getting the data from the drop
-  nsCOMPtr<nsITransferable> trans;
-  rv = PrepareHTMLTransferable(getter_AddRefs(trans), bHavePrivateHTMLFlavor);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(trans, NS_OK);  // NS_ERROR_FAILURE; SHOULD WE FAIL?
+nsresult nsHTMLEditor::InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
+                                              PRInt32 aIndex,
+                                              nsIDOMDocument *aSourceDoc,
+                                              nsIDOMNode *aDestinationNode,
+                                              PRInt32 aDestOffset,
+                                              bool aDoDeleteSelection)
+{
+  nsresult rv = NS_OK;
+
+  nsCOMPtr<nsIDOMDOMStringList> types;
+  aDataTransfer->MozTypesAt(aIndex, getter_AddRefs(types));
 
-  PRUint32 numItems = 0; 
-  rv = dragSession->GetNumDropItems(&numItems);
-  NS_ENSURE_SUCCESS(rv, rv);
+  bool hasPrivateHTMLFlavor;
+  types->Contains(NS_LITERAL_STRING(kHTMLContext), &hasPrivateHTMLFlavor);
 
-  // Combine any deletion and drop insertion into one transaction
-  nsAutoEditBatch beginBatching(this);
-
-  // We never have to delete if selection is already collapsed
-  bool deleteSelection = false;
-  nsCOMPtr<nsIDOMNode> newSelectionParent;
-  PRInt32 newSelectionOffset = 0;
+  bool isText = IsPlaintextEditor();
+  bool isSafe = IsSafeToInsertData(aSourceDoc);
+  
+  PRUint32 length;
+  types->GetLength(&length);
+  for (PRUint32 t = 0; t < length; t++) {
+    nsAutoString type;
+    types->Item(t, type);
 
-  // Source doc is null if source is *not* the current editor document
-  nsCOMPtr<nsIDOMDocument> srcdomdoc;
-  rv = dragSession->GetSourceDocument(getter_AddRefs(srcdomdoc));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRUint32 i; 
-  bool doPlaceCaret = true;
-  for (i = 0; i < numItems; ++i)
-  {
-    rv = dragSession->GetData(trans, i);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(trans, NS_OK); // NS_ERROR_FAILURE; Should we fail?
+    if (!isText) {
+      if (type.EqualsLiteral(kFileMime) ||
+          type.EqualsLiteral(kJPEGImageMime) ||
+          type.EqualsLiteral(kPNGImageMime) ||
+          type.EqualsLiteral(kGIFImageMime)) {
+        nsCOMPtr<nsIVariant> variant;
+        aDataTransfer->MozGetDataAt(type, aIndex, getter_AddRefs(variant));
+        if (variant) {
+          nsCOMPtr<nsISupports> object;
+          variant->GetAsISupports(getter_AddRefs(object));
+          rv = InsertObject(NS_ConvertUTF16toUTF8(type).get(), object, isSafe,
+                            aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
+          if (NS_SUCCEEDED(rv))
+            return NS_OK;
+        }
+      }
+      else if (!hasPrivateHTMLFlavor && type.EqualsLiteral(kNativeHTMLMime)) {
+        nsAutoString text;
+        GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kNativeHTMLMime), aIndex, text);
+        NS_ConvertUTF16toUTF8 cfhtml(text);
 
-    // get additional html copy hints, if present
-    nsAutoString contextStr, infoStr;
-    nsCOMPtr<nsISupports> contextDataObj, infoDataObj;
-    PRUint32 contextLen, infoLen;
-    nsCOMPtr<nsISupportsString> textDataObj;
-    
-    nsCOMPtr<nsITransferable> contextTrans =
-                      do_CreateInstance("@mozilla.org/widget/transferable;1");
-    NS_ENSURE_TRUE(contextTrans, NS_ERROR_NULL_POINTER);
-    contextTrans->AddDataFlavor(kHTMLContext);
-    dragSession->GetData(contextTrans, i);
-    contextTrans->GetTransferData(kHTMLContext, getter_AddRefs(contextDataObj), &contextLen);
+        nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
+           
+        rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
+        if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
+        {
+          nsAutoEditBatch beginBatching(this);
+          rv = DoInsertHTMLWithContext(cffragment,
+                                       cfcontext, cfselection, type,
+                                       aSourceDoc,
+                                       aDestinationNode, aDestOffset,
+                                       aDoDeleteSelection,
+                                       isSafe);
+          if (NS_SUCCEEDED(rv))
+            return NS_OK;
+        }
+      }
+      else if (type.EqualsLiteral(kHTMLMime)) {
+        nsAutoString text, contextString, infoString;
+        GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
+        GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), aIndex, contextString);
+        GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), aIndex, infoString);
 
-    nsCOMPtr<nsITransferable> infoTrans =
-                      do_CreateInstance("@mozilla.org/widget/transferable;1");
-    NS_ENSURE_TRUE(infoTrans, NS_ERROR_NULL_POINTER);
-    infoTrans->AddDataFlavor(kHTMLInfo);
-    dragSession->GetData(infoTrans, i);
-    infoTrans->GetTransferData(kHTMLInfo, getter_AddRefs(infoDataObj), &infoLen);
-    
-    if (contextDataObj)
-    {
-      nsAutoString text;
-      textDataObj = do_QueryInterface(contextDataObj);
-      textDataObj->GetData(text);
-      NS_ASSERTION(text.Length() <= (contextLen/2), "Invalid length!");
-      contextStr.Assign(text.get(), contextLen / 2);
-    }
-    
-    if (infoDataObj)
-    {
-      nsAutoString text;
-      textDataObj = do_QueryInterface(infoDataObj);
-      textDataObj->GetData(text);
-      NS_ASSERTION(text.Length() <= (infoLen/2), "Invalid length!");
-      infoStr.Assign(text.get(), infoLen / 2);
+        nsAutoEditBatch beginBatching(this);
+        if (type.EqualsLiteral(kHTMLMime)) {
+          rv = DoInsertHTMLWithContext(text,
+                                       contextString, infoString, type,
+                                       aSourceDoc,
+                                       aDestinationNode, aDestOffset,
+                                       aDoDeleteSelection,
+                                       isSafe);
+          if (NS_SUCCEEDED(rv))
+            return NS_OK;
+        }
+      }
     }
 
-    if (doPlaceCaret)
-    {
-      // check if the user pressed the key to force a copy rather than a move
-      // if we run into problems here, we'll just assume the user doesn't want a copy
-      bool userWantsCopy = false;
-
-      nsCOMPtr<nsIDOMUIEvent> uiEvent = do_QueryInterface(aDropEvent);
-      NS_ENSURE_TRUE(uiEvent, NS_ERROR_FAILURE);
-
-      nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aDropEvent);
-      if (mouseEvent) {
-#if defined(XP_MACOSX)
-        mouseEvent->GetAltKey(&userWantsCopy);
-#else
-        mouseEvent->GetCtrlKey(&userWantsCopy);
-#endif
-      }
-
-      // Current doc is destination
-      nsCOMPtr<nsIDOMDocument> destdomdoc; 
-      rv = GetDocument(getter_AddRefs(destdomdoc)); 
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsCOMPtr<nsISelection> selection;
-      rv = GetSelection(getter_AddRefs(selection));
-      NS_ENSURE_SUCCESS(rv, rv);
-      NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
-
-      bool isCollapsed;
-      rv = selection->GetIsCollapsed(&isCollapsed);
-      NS_ENSURE_SUCCESS(rv, rv);
-      
-      // Parent and offset under the mouse cursor
-      rv = uiEvent->GetRangeParent(getter_AddRefs(newSelectionParent));
-      NS_ENSURE_SUCCESS(rv, rv);
-      NS_ENSURE_TRUE(newSelectionParent, NS_ERROR_FAILURE);
-
-      rv = uiEvent->GetRangeOffset(&newSelectionOffset);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      // XXX: This userSelectNode code is a workaround for bug 195957.
-      //
-      // Check to see if newSelectionParent is part of a "-moz-user-select: all"
-      // subtree. If it is, we need to make sure we don't drop into it!
-
-      nsCOMPtr<nsIDOMNode> userSelectNode = FindUserSelectAllNode(newSelectionParent);
-
-      if (userSelectNode)
-      {
-        // The drop is happening over a "-moz-user-select: all"
-        // subtree so make sure the content we insert goes before
-        // the root of the subtree.
-        //
-        // XXX: Note that inserting before the subtree matches the
-        //      current behavior when dropping on top of an image.
-        //      The decision for dropping before or after the
-        //      subtree should really be done based on coordinates.
-
-        rv = GetNodeLocation(userSelectNode, address_of(newSelectionParent),
-                             &newSelectionOffset);
+    if (type.EqualsLiteral(kTextMime) ||
+        type.EqualsLiteral(kMozTextInternal)) {
+      nsAutoString text;
+      GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
 
-        NS_ENSURE_SUCCESS(rv, rv);
-        NS_ENSURE_TRUE(newSelectionParent, NS_ERROR_FAILURE);
-      }
-
-      // We never have to delete if selection is already collapsed
-      bool cursorIsInSelection = false;
-
-      // Check if mouse is in the selection
-      if (!isCollapsed)
-      {
-        PRInt32 rangeCount;
-        rv = selection->GetRangeCount(&rangeCount);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        for (PRInt32 j = 0; j < rangeCount; j++)
-        {
-          nsCOMPtr<nsIDOMRange> range;
-
-          rv = selection->GetRangeAt(j, getter_AddRefs(range));
-          if (NS_FAILED(rv) || !range) 
-            continue;//don't bail yet, iterate through them all
-
-          rv = range->IsPointInRange(newSelectionParent, newSelectionOffset, &cursorIsInSelection);
-          if(cursorIsInSelection)
-            break;
-        }
-        if (cursorIsInSelection)
-        {
-          // Dragging within same doc can't drop on itself -- leave!
-          // (We shouldn't get here - drag event shouldn't have started if over selection)
-          if (srcdomdoc == destdomdoc)
-            return NS_OK;
-          
-          // Dragging from another window onto a selection
-          // XXX Decision made to NOT do this,
-          //     note that 4.x does replace if dropped on
-          //deleteSelection = true;
-        }
-        else 
-        {
-          // We are NOT over the selection
-          if (srcdomdoc == destdomdoc)
-          {
-            // Within the same doc: delete if user doesn't want to copy
-            deleteSelection = !userWantsCopy;
-          }
-          else
-          {
-            // Different source doc: Don't delete
-            deleteSelection = false;
-          }
-        }
-      }
-
-      // We have to figure out whether to delete/relocate caret only once
-      doPlaceCaret = false;
+      nsAutoEditBatch beginBatching(this);
+      rv = InsertTextAt(text, aDestinationNode, aDestOffset, aDoDeleteSelection);
+      if (NS_SUCCEEDED(rv))
+        return NS_OK;
     }
-    
-    // handle transferable hooks
-    if (!nsEditorHookUtils::DoInsertionHook(domdoc, aDropEvent, trans))
-      return NS_OK;
-
-    // Beware! This may flush notifications via synchronous
-    // ScrollSelectionIntoView.
-    rv = InsertFromTransferable(trans, srcdomdoc, contextStr, infoStr,
-                                newSelectionParent,
-                                newSelectionOffset, deleteSelection);
   }
 
   return rv;
 }
 
-NS_IMETHODIMP nsHTMLEditor::CanDrag(nsIDOMEvent *aDragEvent, bool *aCanDrag)
-{
-  return nsPlaintextEditor::CanDrag(aDragEvent, aCanDrag);
-}
-
-nsresult
-nsHTMLEditor::PutDragDataInTransferable(nsITransferable **aTransferable)
-{
-  NS_ENSURE_ARG_POINTER(aTransferable);
-  *aTransferable = nsnull;
-  nsCOMPtr<nsIDocumentEncoder> docEncoder;
-  nsresult rv = SetupDocEncoder(getter_AddRefs(docEncoder));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
-
-  // grab a string
-  nsAutoString buffer, parents, info;
-
-  // find out if we're a plaintext control or not
-  if (!IsPlaintextEditor())
-  {
-    // encode the selection as html with contextual info
-    rv = docEncoder->EncodeToStringWithContext(parents, info, buffer);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else
-  {
-    // encode the selection
-    rv = docEncoder->EncodeToString(buffer);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // if we have an empty string, we're done; otherwise continue
-  if ( buffer.IsEmpty() )
-    return NS_OK;
-
-  nsCOMPtr<nsISupportsString> dataWrapper, contextWrapper, infoWrapper;
-
-  dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = dataWrapper->SetData(buffer);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  /* create html flavor transferable */
-  nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1");
-  NS_ENSURE_TRUE(trans, NS_ERROR_FAILURE);
-
-  if (IsPlaintextEditor())
-  {
-    // Add the unicode flavor to the transferable
-    rv = trans->AddDataFlavor(kUnicodeMime);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // QI the data object an |nsISupports| so that when the transferable holds
-    // onto it, it will addref the correct interface.
-    nsCOMPtr<nsISupports> genericDataObj(do_QueryInterface(dataWrapper));
-    rv = trans->SetTransferData(kUnicodeMime, genericDataObj,
-                                buffer.Length() * sizeof(PRUnichar));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else
-  {
-    contextWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
-    NS_ENSURE_TRUE(contextWrapper, NS_ERROR_FAILURE);
-    infoWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
-    NS_ENSURE_TRUE(infoWrapper, NS_ERROR_FAILURE);
-
-    contextWrapper->SetData(parents);
-    infoWrapper->SetData(info);
-
-    rv = trans->AddDataFlavor(kHTMLMime);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsIFormatConverter> htmlConverter =
-             do_CreateInstance("@mozilla.org/widget/htmlformatconverter;1");
-    NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE);
-
-    rv = trans->SetConverter(htmlConverter);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsISupports> genericDataObj(do_QueryInterface(dataWrapper));
-    rv = trans->SetTransferData(kHTMLMime, genericDataObj,
-                                buffer.Length() * sizeof(PRUnichar));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!parents.IsEmpty())
-    {
-      // Add the htmlcontext DataFlavor to the transferable
-      trans->AddDataFlavor(kHTMLContext);
-      genericDataObj = do_QueryInterface(contextWrapper);
-      trans->SetTransferData(kHTMLContext, genericDataObj,
-                             parents.Length() * sizeof(PRUnichar));
-    }
-    if (!info.IsEmpty())
-    {
-      // Add the htmlinfo DataFlavor to the transferable
-      trans->AddDataFlavor(kHTMLInfo);
-      genericDataObj = do_QueryInterface(infoWrapper);
-      trans->SetTransferData(kHTMLInfo, genericDataObj,
-                             info.Length() * sizeof(PRUnichar));
-    }
-  }
-
-  *aTransferable = trans; 
-  NS_ADDREF(*aTransferable);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
-{
-  return nsPlaintextEditor::DoDrag(aDragEvent);
-}
-
 bool nsHTMLEditor::HavePrivateHTMLFlavor(nsIClipboard *aClipboard)
 {
   // check the clipboard for our special kHTMLContext flavor.  If that is there, we know
   // we have our own internal html format on clipboard.
   
   NS_ENSURE_TRUE(aClipboard, false);
   bool bHavePrivateHTMLFlavor = false;
   
@@ -1809,18 +1592,16 @@ NS_IMETHODIMP nsHTMLEditor::Paste(PRInt3
       }
 
       // handle transferable hooks
       nsCOMPtr<nsIDOMDocument> domdoc;
       GetDocument(getter_AddRefs(domdoc));
       if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, trans))
         return NS_OK;
 
-      // Beware! This may flush notifications via synchronous
-      // ScrollSelectionIntoView.
       rv = InsertFromTransferable(trans, nsnull, contextStr, infoStr,
                                   nsnull, 0, true);
     }
   }
 
   return rv;
 }
 
@@ -1830,18 +1611,16 @@ NS_IMETHODIMP nsHTMLEditor::PasteTransfe
     return NS_OK;
 
   // handle transferable hooks
   nsCOMPtr<nsIDOMDocument> domdoc;
   GetDocument(getter_AddRefs(domdoc));
   if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
     return NS_OK;
 
-  // Beware! This may flush notifications via synchronous
-  // ScrollSelectionIntoView.
   nsAutoString contextStr, infoStr;
   return InsertFromTransferable(aTransferable, nsnull, contextStr, infoStr,
                                 nsnull, 0, true);
 }
 
 // 
 // HTML PasteNoFormatting. Ignore any HTML styles and formating in paste source
 //
@@ -1859,18 +1638,16 @@ NS_IMETHODIMP nsHTMLEditor::PasteNoForma
   nsCOMPtr<nsITransferable> trans;
   rv = nsPlaintextEditor::PrepareTransferable(getter_AddRefs(trans));
   if (NS_SUCCEEDED(rv) && trans)
   {
     // Get the Data from the clipboard  
     if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
     {
       const nsAFlatString& empty = EmptyString();
-      // Beware! This may flush notifications via synchronous
-      // ScrollSelectionIntoView.
       rv = InsertFromTransferable(trans, nsnull, empty, empty, nsnull, 0,
                                   true);
     }
   }
 
   return rv;
 }
 
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -108,17 +108,16 @@ static char hrefText[] = "href";
 static char anchorTxt[] = "anchor";
 static char namedanchorText[] = "namedanchor";
 
 #define IsLinkTag(s) (s.EqualsIgnoreCase(hrefText))
 #define IsNamedAnchorTag(s) (s.EqualsIgnoreCase(anchorTxt) || s.EqualsIgnoreCase(namedanchorText))
 
 nsHTMLEditor::nsHTMLEditor()
 : nsPlaintextEditor()
-, mIgnoreSpuriousDragEvent(false)
 , mCRInParagraphCreatesParagraph(false)
 , mSelectedCellIndex(0)
 , mIsObjectResizingEnabled(true)
 , mIsResizing(false)
 , mIsAbsolutelyPositioningEnabled(true)
 , mResizedObjectIsAbsolutelyPositioned(false)
 , mGrabberClicked(false)
 , mIsMoving(false)
@@ -5307,23 +5306,16 @@ nsHTMLEditor::EndUpdateViewBatch()
     NS_ENSURE_SUCCESS(res, res);
     NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
     res = CheckSelectionStateForAnonymousButtons(selection);
   }
   return res;
 }
 
 NS_IMETHODIMP
-nsHTMLEditor::IgnoreSpuriousDragEvent(bool aIgnoreSpuriousDragEvent)
-{
-  mIgnoreSpuriousDragEvent = aIgnoreSpuriousDragEvent;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsHTMLEditor::GetSelectionContainer(nsIDOMElement ** aReturn)
 {
   nsCOMPtr<nsISelection>selection;
   nsresult res = GetSelection(getter_AddRefs(selection));
   // if we don't get the selection, just skip this
   if (NS_FAILED(res) || !selection) return res;
 
   bool bCollapsed;
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -365,18 +365,17 @@ public:
                               nsresult aStatus);
 
   /* ------------ Utility Routines, not part of public API -------------- */
   NS_IMETHOD TypedText(const nsAString& aString, PRInt32 aAction);
   nsresult InsertNodeAtPoint( nsIDOMNode *aNode, 
                               nsCOMPtr<nsIDOMNode> *ioParent, 
                               PRInt32 *ioOffset, 
                               bool aNoEmptyNodes);
-  already_AddRefed<nsIDOMNode> FindUserSelectAllNode(nsIDOMNode* aNode);
-                                
+  virtual already_AddRefed<nsIDOMNode> FindUserSelectAllNode(nsIDOMNode* aNode);
 
   /** returns the absolute position of the end points of aSelection
     * in the document as a text stream.
     */
   nsresult GetTextSelectionOffsets(nsISelection *aSelection,
                                    PRInt32 &aStartOffset, 
                                    PRInt32 &aEndOffset);
 
@@ -567,28 +566,43 @@ protected:
     *                        (usually true, unless those characters
     *                        have already been added.)
     * @return aNodeInserted  The node spanning the insertion, if applicable.
     *                        If aAddCites is false, this will be null.
     */
   NS_IMETHOD InsertAsPlaintextQuotation(const nsAString & aQuotedText,
                                         bool aAddCites,
                                         nsIDOMNode **aNodeInserted);
+  // Return true if the data is safe to insert as the source and destination
+  // principals match, or we are in a editor context where this doesn't matter.
+  // Otherwise, the data must be sanitized first.
+  bool IsSafeToInsertData(nsIDOMDocument* aSourceDoc);
+
+  nsresult InsertObject(const char* aType, nsISupports* aObject, bool aIsSafe,
+                        nsIDOMDocument *aSourceDoc,
+                        nsIDOMNode *aDestinationNode,
+                        PRInt32 aDestOffset,
+                        bool aDoDeleteSelection);
 
   // factored methods for handling insertion of data from transferables (drag&drop or clipboard)
   NS_IMETHOD PrepareTransferable(nsITransferable **transferable);
   NS_IMETHOD PrepareHTMLTransferable(nsITransferable **transferable, bool havePrivFlavor);
-  nsresult   PutDragDataInTransferable(nsITransferable **aTransferable);
   NS_IMETHOD InsertFromTransferable(nsITransferable *transferable, 
                                     nsIDOMDocument *aSourceDoc,
                                     const nsAString & aContextStr,
                                     const nsAString & aInfoStr,
                                     nsIDOMNode *aDestinationNode,
                                     PRInt32 aDestinationOffset,
                                     bool aDoDeleteSelection);
+  nsresult InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
+                                  PRInt32 aIndex,
+                                  nsIDOMDocument *aSourceDoc,
+                                  nsIDOMNode *aDestinationNode,
+                                  PRInt32 aDestOffset,
+                                  bool aDoDeleteSelection);
   bool HavePrivateHTMLFlavor( nsIClipboard *clipboard );
   nsresult   ParseCFHTML(nsCString & aCfhtml, PRUnichar **aStuffToPaste, PRUnichar **aCfcontext);
   nsresult   DoContentFilterCallback(const nsAString &aFlavor,
                                      nsIDOMDocument *aSourceDoc,
                                      bool aWillDeleteSelection,
                                      nsIDOMNode **aFragmentAsNode,      
                                      nsIDOMNode **aFragStartNode,
                                      PRInt32 *aFragStartOffset,
@@ -717,19 +731,16 @@ protected:
   nsresult IsFirstEditableChild( nsIDOMNode *aNode, bool *aOutIsFirst);
   nsresult IsLastEditableChild( nsIDOMNode *aNode, bool *aOutIsLast);
   nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
   nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
 
   nsresult GetFirstEditableLeaf( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstLeaf);
   nsresult GetLastEditableLeaf( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastLeaf);
 
-  //XXX Kludge: Used to suppress spurious drag/drop events (bug 50703)
-  bool     mIgnoreSpuriousDragEvent;
-
   nsresult GetInlinePropertyBase(nsIAtom *aProperty, 
                              const nsAString *aAttribute,
                              const nsAString *aValue,
                              bool *aFirst, 
                              bool *aAny, 
                              bool *aAll,
                              nsAString *outValue,
                              bool aCheckDefaults = true);
--- a/editor/libeditor/text/nsPlaintextDataTransfer.cpp
+++ b/editor/libeditor/text/nsPlaintextDataTransfer.cpp
@@ -47,25 +47,27 @@
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMDragEvent.h"
 #include "nsISelection.h"
 #include "nsCRT.h"
 #include "nsServiceManagerUtils.h"
 
 #include "nsIDOMRange.h"
+#include "nsIDOMDOMStringList.h"
 #include "nsIDocumentEncoder.h"
 #include "nsISupportsPrimitives.h"
 
 // Drag & Drop, Clipboard
 #include "nsIClipboard.h"
 #include "nsITransferable.h"
 #include "nsIDragService.h"
 #include "nsIDOMUIEvent.h"
 #include "nsCopySupport.h"
+#include "nsITransferable.h"
 
 // Misc
 #include "nsEditorUtils.h"
 #include "nsContentCID.h"
 #include "nsISelectionPrivate.h"
 #include "nsFrameSelection.h"
 #include "nsEventDispatcher.h"
 #include "nsContentUtils.h"
@@ -146,50 +148,58 @@ NS_IMETHODIMP nsPlaintextEditor::InsertT
       nsAutoEditBatch beginBatching(this);
       rv = InsertTextAt(stuffToPaste, aDestinationNode, aDestOffset, aDoDeleteSelection);
     }
   }
   NS_Free(bestFlavor);
       
   // Try to scroll the selection into view if the paste/drop succeeded
 
-  // After ScrollSelectionIntoView(), the pending notifications might be flushed
-  // and PresShell/PresContext/Frames may be dead. See bug 418470.
   if (NS_SUCCEEDED(rv))
     ScrollSelectionIntoView(false);
 
   return rv;
 }
 
-NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
+nsresult nsPlaintextEditor::InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
+                                                   PRInt32 aIndex,
+                                                   nsIDOMDocument *aSourceDoc,
+                                                   nsIDOMNode *aDestinationNode,
+                                                   PRInt32 aDestOffset,
+                                                   bool aDoDeleteSelection)
+{
+  nsCOMPtr<nsIVariant> data;
+  aDataTransfer->MozGetDataAt(NS_LITERAL_STRING("text/plain"), aIndex,
+                              getter_AddRefs(data));
+  nsAutoString insertText;
+  data->GetAsAString(insertText);
+  nsContentUtils::PlatformToDOMLineBreaks(insertText);
+
+  nsAutoEditBatch beginBatching(this);
+  return InsertTextAt(insertText, aDestinationNode, aDestOffset, aDoDeleteSelection);
+}
+
+nsresult nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
 {
   ForceCompositionEnd();
-  
-  nsresult rv;
-  nsCOMPtr<nsIDragService> dragService = 
-           do_GetService("@mozilla.org/widget/dragservice;1", &rv);
+
+  nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aDropEvent));
+  NS_ENSURE_TRUE(dragEvent, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
+  nsresult rv = dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIDragSession> dragSession;
-  dragService->GetCurrentSession(getter_AddRefs(dragSession));
-  NS_ENSURE_TRUE(dragSession, NS_OK);
-
   // Current doc is destination
   nsCOMPtr<nsIDOMDocument> destdomdoc; 
   rv = GetDocument(getter_AddRefs(destdomdoc)); 
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Get the nsITransferable interface for getting the data from the drop
-  nsCOMPtr<nsITransferable> trans;
-  rv = PrepareTransferable(getter_AddRefs(trans));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(trans, NS_OK);  // NS_ERROR_FAILURE; SHOULD WE FAIL?
-
-  PRUint32 numItems = 0; 
-  rv = dragSession->GetNumDropItems(&numItems);
+  PRUint32 numItems = 0;
+  rv = dataTransfer->GetMozItemCount(&numItems);
   NS_ENSURE_SUCCESS(rv, rv);
   if (numItems < 1) return NS_ERROR_FAILURE;  // nothing to drop?
 
   // Combine any deletion and drop insertion into one transaction
   nsAutoEditBatch beginBatching(this);
 
   bool deleteSelection = false;
 
@@ -211,16 +221,45 @@ NS_IMETHODIMP nsPlaintextEditor::InsertF
   rv = GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
   bool isCollapsed;
   rv = selection->GetIsCollapsed(&isCollapsed);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsIDOMNode> sourceNode;
+  dataTransfer->GetMozSourceNode(getter_AddRefs(sourceNode));
+
+  nsCOMPtr<nsIDOMDocument> srcdomdoc;
+  if (sourceNode) {
+    sourceNode->GetOwnerDocument(getter_AddRefs(srcdomdoc));
+    NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
+  }
+
+  // Only the nsHTMLEditor::FindUserSelectAllNode returns a node.
+  nsCOMPtr<nsIDOMNode> userSelectNode = FindUserSelectAllNode(newSelectionParent);
+  if (userSelectNode)
+  {
+    // The drop is happening over a "-moz-user-select: all"
+    // subtree so make sure the content we insert goes before
+    // the root of the subtree.
+    //
+    // XXX: Note that inserting before the subtree matches the
+    //      current behavior when dropping on top of an image.
+    //      The decision for dropping before or after the
+    //      subtree should really be done based on coordinates.
+
+    rv = GetNodeLocation(userSelectNode, address_of(newSelectionParent),
+                         &newSelectionOffset);
+
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_TRUE(newSelectionParent, NS_ERROR_FAILURE);
+  }
+
   // Check if mouse is in the selection
   // if so, jump through some hoops to determine if mouse is over selection (bail)
   // and whether user wants to copy selection or delete it
   if (!isCollapsed)
   {
     // We never have to delete if selection is already collapsed
     bool cursorIsInSelection = false;
 
@@ -235,22 +274,16 @@ NS_IMETHODIMP nsPlaintextEditor::InsertF
       if (NS_FAILED(rv) || !range) 
         continue;  // don't bail yet, iterate through them all
 
       rv = range->IsPointInRange(newSelectionParent, newSelectionOffset, &cursorIsInSelection);
       if (cursorIsInSelection)
         break;
     }
 
-    // Source doc is null if source is *not* the current editor document
-    // Current doc is destination (set earlier)
-    nsCOMPtr<nsIDOMDocument> srcdomdoc;
-    rv = dragSession->GetSourceDocument(getter_AddRefs(srcdomdoc));
-    NS_ENSURE_SUCCESS(rv, rv);
-
     if (cursorIsInSelection)
     {
       // Dragging within same doc can't drop on itself -- leave!
       if (srcdomdoc == destdomdoc)
         return NS_OK;
 
       // Dragging from another window onto a selection
       // XXX Decision made to NOT do this,
@@ -258,162 +291,48 @@ NS_IMETHODIMP nsPlaintextEditor::InsertF
       //deleteSelection = true;
     }
     else 
     {
       // We are NOT over the selection
       if (srcdomdoc == destdomdoc)
       {
         // Within the same doc: delete if user doesn't want to copy
-        PRUint32 action;
-        dragSession->GetDragAction(&action);
-        deleteSelection = !(action & nsIDragService::DRAGDROP_ACTION_COPY);
+        PRUint32 dropEffect;
+        dataTransfer->GetDropEffectInt(&dropEffect);
+        deleteSelection = !(dropEffect & nsIDragService::DRAGDROP_ACTION_COPY);
       }
       else
       {
         // Different source doc: Don't delete
         deleteSelection = false;
       }
     }
   }
 
-  nsCOMPtr<nsIContent> newSelectionContent =
-    do_QueryInterface(newSelectionParent);
-  nsIContent *content = newSelectionContent;
-
-  while (content) {
-    nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(content));
-
-    if (formControl && !formControl->AllowDrop()) {
-      // Don't allow dropping into a form control that doesn't allow being
-      // dropped into.
-
-      return NS_OK;
-    }
-
-    content = content->GetParent();
-  }
-
-  PRUint32 i; 
-  for (i = 0; i < numItems; ++i)
-  {
-    rv = dragSession->GetData(trans, i);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(trans, NS_OK); // NS_ERROR_FAILURE; Should we fail?
-
-    // Beware! This may flush notifications via synchronous
-    // ScrollSelectionIntoView.
-    rv = InsertTextFromTransferable(trans, newSelectionParent, newSelectionOffset, deleteSelection);
-  }
-
-  return rv;
-}
-
-NS_IMETHODIMP nsPlaintextEditor::CanDrag(nsIDOMEvent *aDragEvent, bool *aCanDrag)
-{
-  NS_ENSURE_TRUE(aCanDrag, NS_ERROR_NULL_POINTER);
-  /* we really should be checking the XY coordinates of the mouseevent and ensure that
-   * that particular point is actually within the selection (not just that there is a selection)
-   */
-  *aCanDrag = false;
- 
-  // KLUDGE to work around bug 50703
-  // After double click and object property editing, 
-  //  we get a spurious drag event
-  if (mIgnoreSpuriousDragEvent)
-  {
-    mIgnoreSpuriousDragEvent = false;
-    return NS_OK;
-  }
-   
-  nsCOMPtr<nsISelection> selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
-    
-  bool isCollapsed;
-  res = selection->GetIsCollapsed(&isCollapsed);
-  NS_ENSURE_SUCCESS(res, res);
-  
-  // if we are collapsed, we have no selection so nothing to drag
-  if ( isCollapsed )
-    return NS_OK;
-
-  nsCOMPtr<nsIDOMEventTarget> eventTarget;
-
-  nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aDragEvent));
-  if (nsevent) {
-    res = nsevent->GetTmpRealOriginalTarget(getter_AddRefs(eventTarget));
-    NS_ENSURE_SUCCESS(res, res);
-  }
-
-  if (eventTarget)
-  {
-    nsCOMPtr<nsIDOMNode> eventTargetDomNode = do_QueryInterface(eventTarget);
-    if ( eventTargetDomNode )
-    {
-      bool isTargetedCorrectly = false;
-      res = selection->ContainsNode(eventTargetDomNode, false, &isTargetedCorrectly);
-      NS_ENSURE_SUCCESS(res, res);
-
-      *aCanDrag = isTargetedCorrectly;
+  if (IsPlaintextEditor()) {
+    nsCOMPtr<nsIContent> content = do_QueryInterface(newSelectionParent);
+    while (content) {
+      nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(content));
+      if (formControl && !formControl->AllowDrop()) {
+        // Don't allow dropping into a form control that doesn't allow being
+        // dropped into.
+        return NS_OK;
+      }
+      content = content->GetParent();
     }
   }
 
-  return res;
-}
-
-NS_IMETHODIMP nsPlaintextEditor::DoDrag(nsIDOMEvent *aDragEvent)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsITransferable> trans;
-  rv = PutDragDataInTransferable(getter_AddRefs(trans));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(trans, NS_OK); // maybe there was nothing to copy?
-
- /* get the drag service */
-  nsCOMPtr<nsIDragService> dragService = 
-           do_GetService("@mozilla.org/widget/dragservice;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  /* create an array of transferables */
-  nsCOMPtr<nsISupportsArray> transferableArray;
-  NS_NewISupportsArray(getter_AddRefs(transferableArray));
-  NS_ENSURE_TRUE(transferableArray, NS_ERROR_OUT_OF_MEMORY);
-
-  /* add the transferable to the array */
-  rv = transferableArray->AppendElement(trans);
-  NS_ENSURE_SUCCESS(rv, rv);
+  for (PRUint32 i = 0; i < numItems; ++i) {
+    InsertFromDataTransfer(dataTransfer, i, srcdomdoc, newSelectionParent,
+                           newSelectionOffset, deleteSelection);
+  }
 
-  // check our transferable hooks (if any)
-  nsCOMPtr<nsIDOMDocument> domdoc;
-  GetDocument(getter_AddRefs(domdoc));
-
-  /* invoke drag */
-  nsCOMPtr<nsIDOMEventTarget> eventTarget;
-  rv = aDragEvent->GetTarget(getter_AddRefs(eventTarget));
-  NS_ENSURE_SUCCESS(rv, rv);
-  nsCOMPtr<nsIDOMNode> domnode = do_QueryInterface(eventTarget);
-
-  nsCOMPtr<nsIScriptableRegion> selRegion;
-  nsCOMPtr<nsISelection> selection;
-  rv = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  unsigned int flags;
-  // in some cases we'll want to cut rather than copy... hmmmmm...
-  flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE;
-
-  nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aDragEvent));
-  rv = dragService->InvokeDragSessionWithSelection(selection, transferableArray,
-                                                   flags, dragEvent, nsnull);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  aDragEvent->StopPropagation();
-  aDragEvent->PreventDefault();
+  if (NS_SUCCEEDED(rv))
+    ScrollSelectionIntoView(false);
 
   return rv;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::Paste(PRInt32 aSelectionType)
 {
   if (!FireClipboardEvent(NS_PASTE))
     return NS_OK;
@@ -433,18 +352,16 @@ NS_IMETHODIMP nsPlaintextEditor::Paste(P
     if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
     {
       // handle transferable hooks
       nsCOMPtr<nsIDOMDocument> domdoc;
       GetDocument(getter_AddRefs(domdoc));
       if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, trans))
         return NS_OK;
 
-      // Beware! This may flush notifications via synchronous
-      // ScrollSelectionIntoView.
       rv = InsertTextFromTransferable(trans, nsnull, nsnull, true);
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP nsPlaintextEditor::PasteTransferable(nsITransferable *aTransferable)
@@ -456,18 +373,16 @@ NS_IMETHODIMP nsPlaintextEditor::PasteTr
     return NS_OK;
 
   // handle transferable hooks
   nsCOMPtr<nsIDOMDocument> domdoc;
   GetDocument(getter_AddRefs(domdoc));
   if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
     return NS_OK;
 
-  // Beware! This may flush notifications via synchronous
-  // ScrollSelectionIntoView.
   return InsertTextFromTransferable(aTransferable, nsnull, nsnull, true);
 }
 
 NS_IMETHODIMP nsPlaintextEditor::CanPaste(PRInt32 aSelectionType, bool *aCanPaste)
 {
   NS_ENSURE_ARG_POINTER(aCanPaste);
   *aCanPaste = false;
 
@@ -516,107 +431,8 @@ NS_IMETHODIMP nsPlaintextEditor::CanPast
                                                &dataLen);
   if (NS_SUCCEEDED(rv) && data)
     *aCanPaste = true;
   else
     *aCanPaste = false;
   
   return NS_OK;
 }
-
-
-nsresult
-nsPlaintextEditor::SetupDocEncoder(nsIDocumentEncoder **aDocEncoder)
-{
-  nsCOMPtr<nsIDOMDocument> domDoc;
-  nsresult rv = GetDocument(getter_AddRefs(domDoc));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // find out if we're a plaintext control or not
-  // get correct mimeType and document encoder flags set
-  nsAutoString mimeType;
-  PRUint32 docEncoderFlags = 0;
-  if (IsPlaintextEditor())
-  {
-    docEncoderFlags |= nsIDocumentEncoder::OutputBodyOnly | nsIDocumentEncoder::OutputPreformatted;
-    mimeType.AssignLiteral(kUnicodeMime);
-  }
-  else
-    mimeType.AssignLiteral(kHTMLMime);
-
-  // set up docEncoder
-  nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(NS_HTMLCOPY_ENCODER_CONTRACTID);
-  NS_ENSURE_TRUE(encoder, NS_ERROR_OUT_OF_MEMORY);
-
-  rv = encoder->Init(domDoc, mimeType, docEncoderFlags);
-  NS_ENSURE_SUCCESS(rv, rv);
-    
-  /* get the selection to be dragged */
-  nsCOMPtr<nsISelection> selection;
-  rv = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = encoder->SetSelection(selection);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aDocEncoder = encoder;
-  NS_ADDREF(*aDocEncoder);
-  return NS_OK;
-}
-
-nsresult
-nsPlaintextEditor::PutDragDataInTransferable(nsITransferable **aTransferable)
-{
-  *aTransferable = nsnull;
-  nsCOMPtr<nsIDocumentEncoder> docEncoder;
-  nsresult rv = SetupDocEncoder(getter_AddRefs(docEncoder));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // grab a string
-  nsAutoString buffer;
-  rv = docEncoder->EncodeToString(buffer);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // if we have an empty string, we're done; otherwise continue
-  if (buffer.IsEmpty())
-    return NS_OK;
-
-  nsCOMPtr<nsISupportsString> dataWrapper =
-                        do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = dataWrapper->SetData(buffer);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  /* create html flavor transferable */
-  nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // find out if we're a plaintext control or not
-  if (IsPlaintextEditor())
-  {
-    // Add the unicode flavor to the transferable
-    rv = trans->AddDataFlavor(kUnicodeMime);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else
-  {
-    rv = trans->AddDataFlavor(kHTMLMime);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsIFormatConverter> htmlConverter = do_CreateInstance("@mozilla.org/widget/htmlformatconverter;1");
-    NS_ENSURE_TRUE(htmlConverter, NS_ERROR_FAILURE);
-
-    rv = trans->SetConverter(htmlConverter);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // QI the data object an |nsISupports| so that when the transferable holds
-  // onto it, it will addref the correct interface.
-  nsCOMPtr<nsISupports> nsisupportsDataWrapper = do_QueryInterface(dataWrapper);
-  rv = trans->SetTransferData(IsPlaintextEditor() ? kUnicodeMime : kHTMLMime,
-                   nsisupportsDataWrapper, buffer.Length() * sizeof(PRUnichar));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aTransferable = trans;
-  NS_ADDREF(*aTransferable);
-  return NS_OK;
-}
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -83,17 +83,16 @@
 #include "nsCopySupport.h"
 
 #include "mozilla/FunctionTimer.h"
 
 using namespace mozilla;
 
 nsPlaintextEditor::nsPlaintextEditor()
 : nsEditor()
-, mIgnoreSpuriousDragEvent(false)
 , mRules(nsnull)
 , mWrapToWindow(false)
 , mWrapColumn(0)
 , mMaxTextLength(-1)
 , mInitTriggerCounter(0)
 , mNewlineHandling(nsIPlaintextEditor::eNewlinesPasteToFirst)
 #ifdef XP_WIN
 , mCaretStyle(1)
--- a/editor/libeditor/text/nsPlaintextEditor.h
+++ b/editor/libeditor/text/nsPlaintextEditor.h
@@ -113,20 +113,16 @@ public:
   NS_IMETHOD CanCut(bool *aCanCut);
   NS_IMETHOD Copy();
   NS_IMETHOD CanCopy(bool *aCanCopy);
   NS_IMETHOD Paste(PRInt32 aSelectionType);
   NS_IMETHOD CanPaste(PRInt32 aSelectionType, bool *aCanPaste);
   NS_IMETHOD PasteTransferable(nsITransferable *aTransferable);
   NS_IMETHOD CanPasteTransferable(nsITransferable *aTransferable, bool *aCanPaste);
 
-  NS_IMETHOD CanDrag(nsIDOMEvent *aDragEvent, bool *aCanDrag);
-  NS_IMETHOD DoDrag(nsIDOMEvent *aDragEvent);
-  NS_IMETHOD InsertFromDrop(nsIDOMEvent* aDropEvent);
-
   NS_IMETHOD OutputToString(const nsAString& aFormatType,
                             PRUint32 aFlags,
                             nsAString& aOutputString);
                             
   NS_IMETHOD OutputToStream(nsIOutputStream* aOutputStream,
                             const nsAString& aFormatType,
                             const nsACString& aCharsetOverride,
                             PRUint32 aFlags);
@@ -162,16 +158,25 @@ public:
                                    PRUint32 &aStartOffset, 
                                    PRUint32 &aEndOffset);
 
   nsresult InsertTextAt(const nsAString &aStringToInsert,
                         nsIDOMNode *aDestinationNode,
                         PRInt32 aDestOffset,
                         bool aDoDeleteSelection);
 
+  virtual nsresult InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
+                                          PRInt32 aIndex,
+                                          nsIDOMDocument *aSourceDoc,
+                                          nsIDOMNode *aDestinationNode,
+                                          PRInt32 aDestOffset,
+                                          bool aDoDeleteSelection);
+
+  virtual nsresult InsertFromDrop(nsIDOMEvent* aDropEvent);
+
   /**