Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 06 May 2014 16:53:11 -0400
changeset 201066 4236bc861bebe7ec47ff18639f048ccf6f7360a4
parent 201065 0202366e8b707a6f3ed8543d490fcedee49c38c4 (current diff)
parent 201049 4e4e0f502969d0fec9e5b5f84b236599f14ab151 (diff)
child 201067 4ed94f132f5b784cabee8ea97a72605f6935aa02
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.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 m-c to fx-team.
mobile/android/chrome/content/browser.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -386,19 +386,16 @@ pref("content.ime.strict_policy", true);
 // On Android, you also need to do the following for the output
 // to show up in logcat:
 //
 // $ adb shell stop
 // $ adb shell setprop log.redirect-stdio true
 // $ adb shell start
 pref("browser.dom.window.dump.enabled", false);
 
-// Turn on the CSP 1.0 parser for Content Security Policy headers
-pref("security.csp.speccompliant", true);
-
 // Default Content Security Policy to apply to privileged and certified apps
 pref("security.apps.privileged.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'");
 // If you change this CSP, make sure to update the fast path in nsCSPService.cpp
 pref("security.apps.certified.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self'");
 
 // Temporarily force-enable GL compositing.  This is default-disabled
 // deep within the bowels of the widgetry system.  Remove me when GL
 // compositing isn't default disabled in widget/android.
--- a/b2g/chrome/content/runapp.js
+++ b/b2g/chrome/content/runapp.js
@@ -26,46 +26,67 @@ window.addEventListener('load', function
   }
 
   // not specified, bail.
   if (appname === null) {
     return;
   }
 
   runAppObj = new AppRunner(appname);
-  Services.obs.addObserver(runAppObj, 'browser-ui-startup-complete', false);
+  Services.obs.addObserver(runAppObj, 'remote-browser-shown', false);
+  Services.obs.addObserver(runAppObj, 'inprocess-browser-shown', false);
 });
 
 window.addEventListener('unload', function() {
   if (runAppObj) {
-    Services.obs.removeObserver(runAppObj, 'browser-ui-startup-complete');
+    Services.obs.removeObserver(runAppObj, 'remote-browser-shown');
+    Services.obs.removeObserver(runAppObj, 'inprocess-browser-shown');
   }
 });
 
 function AppRunner(aName) {
-  this._req = null;
   this._appName = aName;
+  this._apps = [];
 }
 AppRunner.prototype = {
   observe: function(aSubject, aTopic, aData) {
-    if (aTopic == 'browser-ui-startup-complete') {
-      this.doRunApp();
+    let frameLoader = aSubject;
+    // get a ref to the app <iframe>
+    frameLoader.QueryInterface(Ci.nsIFrameLoader);
+    // Ignore notifications that aren't from a BrowserOrApp
+    if (!frameLoader.ownerIsBrowserOrAppFrame) {
+      return;
+    }
+
+    let frame = frameLoader.ownerElement;
+    if (!frame.appManifestURL) { // Ignore all frames but app frames
+      return;
+    }
+
+    if (aTopic == 'remote-browser-shown' ||
+        aTopic == 'inprocess-browser-shown') {
+      this.doRunApp(frame);
     }
   },
 
-  doRunApp: function() {
+  doRunApp: function(currentFrame) {
     // - Get the list of apps since the parameter was specified
-    this._req = navigator.mozApps.mgmt.getAll();
-    this._req.onsuccess = this.getAllSuccess.bind(this);
-    this._req.onerror = this.getAllError.bind(this);
+    if (this._apps.length) {
+      this.getAllSuccess(this._apps, currentFrame)
+    } else {
+      var req = navigator.mozApps.mgmt.getAll();
+      req.onsuccess = function() {
+        this._apps = req.result;
+        this.getAllSuccess(this._apps, currentFrame)
+      }.bind(this);
+      req.onerror = this.getAllError.bind(this);
+    }
   },
 
-  getAllSuccess: function() {
-    let apps = this._req.result;
-
+  getAllSuccess: function(apps, currentFrame) {
     function findAppWithName(name) {
       let normalizedSearchName = name.replace(/[- ]+/g, '').toLowerCase();
 
       for (let i = 0; i < apps.length; i++) {
         let app = apps[i];
         let normalizedAppName =
           app.manifest.name.replace(/[- ]+/g, '').toLowerCase();
         if (normalizedSearchName === normalizedAppName) {
@@ -93,36 +114,53 @@ AppRunner.prototype = {
       Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);
     }
 
     if (this._appName === '') {
       usageAndDie();
       return;
     }
 
+    let appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
+    let currentApp = appsService.getAppByManifestURL(currentFrame.appManifestURL);
+
+    if (!currentApp || currentApp.role !== 'homescreen') {
+      return;
+    }
+
     let app = findAppWithName(this._appName);
     if (!app) {
       dump('Could not find app: "' + this._appName + '". Maybe you meant one of:\n');
       usageAndDie(true);
       return;
     }
 
-    let setReq =
-      navigator.mozSettings.createLock().set({'lockscreen.enabled': false});
-    setReq.onsuccess = function() {
-      // give the event loop 100ms to disable the lock screen
-      window.setTimeout(function() {
-        dump('--runapp launching app: ' + app.manifest.name + '\n');
-        app.launch();
-      }, 100);
-    };
-    setReq.onerror = function() {
-      dump('--runapp failed to disable lock-screen.  Giving up.\n');
-    };
+    currentFrame.addEventListener('mozbrowserloadend', launchApp);
+
+    function launchApp() {
+      currentFrame.removeEventListener('mozbrowserloadend', launchApp);
 
-    dump('--runapp found app: ' + app.manifest.name +
-         ', disabling lock screen...\n');
+      let setReq =
+        navigator.mozSettings.createLock().set({'lockscreen.enabled': false});
+      setReq.onsuccess = function() {
+        // give the event loop 100ms to disable the lock screen
+        window.setTimeout(function() {
+          dump('--runapp launching app: ' + app.manifest.name + '\n');
+          app.launch();
+        }, 100);
+      };
+      setReq.onerror = function() {
+        dump('--runapp failed to disable lock-screen.  Giving up.\n');
+      };
+
+      dump('--runapp found app: ' + app.manifest.name +
+           ', disabling lock screen...\n');
+
+      // Disable observers once we have made the request to launch the app.
+      Services.obs.removeObserver(runAppObj, 'remote-browser-shown');
+      Services.obs.removeObserver(runAppObj, 'inprocess-browser-shown');
+    }
   },
 
   getAllError: function() {
     dump('Problem getting the list of all apps!');
   }
 };
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -595,48 +595,16 @@ SettingsListener.observe("accessibility.
     SettingsListener.observe('gaia.' + pref, null, function(value) {
       if (value) {
         Services.prefs.setCharPref(pref, value);
       }
     });
   });
 })();
 
-// =================== AsyncPanZoom ======================
-SettingsListener.observe('apz.displayport.heuristics', 'default', function(value) {
-  // first reset everything to default
-  Services.prefs.clearUserPref('apz.velocity_bias');
-  Services.prefs.clearUserPref('apz.use_paint_duration');
-  Services.prefs.clearUserPref('apz.x_skate_size_multiplier');
-  Services.prefs.clearUserPref('apz.y_skate_size_multiplier');
-  Services.prefs.clearUserPref('apz.allow-checkerboarding');
-  // and then set the things that we want to change
-  switch (value) {
-  case 'default':
-    break;
-  case 'center-displayport':
-    Services.prefs.setCharPref('apz.velocity_bias', '0.0');
-    break;
-  case 'perfect-paint-times':
-    Services.prefs.setBoolPref('apz.use_paint_duration', false);
-    Services.prefs.setCharPref('apz.velocity_bias', '0.32'); // 16/50 (assumes 16ms paint times instead of 50ms)
-    break;
-  case 'taller-displayport':
-    Services.prefs.setCharPref('apz.y_skate_size_multiplier', '3.5');
-    break;
-  case 'faster-paint':
-    Services.prefs.setCharPref('apz.x_skate_size_multiplier', '1.0');
-    Services.prefs.setCharPref('apz.y_skate_size_multiplier', '1.5');
-    break;
-  case 'no-checkerboard':
-    Services.prefs.setBoolPref('apz.allow-checkerboarding', false);
-    break;
-  }
-});
-
 // =================== Various simple mapping  ======================
 let settingsToObserve = {
   'ril.mms.retrieval_mode': {
     prefName: 'dom.mms.retrieval_mode',
     defaultValue: 'manual'
   },
   'ril.sms.strict7BitEncoding.enabled': {
     prefName: 'dom.sms.strict7BitEncoding',
@@ -661,17 +629,16 @@ let settingsToObserve = {
   'devtools.eventlooplag.threshold': 100,
   'privacy.donottrackheader.enabled': false,
   'apz.force-enable': {
     prefName: 'dom.browser_frames.useAsyncPanZoom',
     defaultValue: false
   },
   'layers.enable-tiles': true,
   'layers.simple-tiles': false,
-  'layers.progressive-paint': false,
   'layers.draw-tile-borders': false,
   'layers.dump': false,
   'debug.fps.enabled': {
     prefName: 'layers.acceleration.draw-fps',
     defaultValue: false
   },
   'debug.paint-flashing.enabled': {
     prefName: 'nglayout.debug.paint_flashing',
--- a/b2g/components/test/mochitest/test_filepicker_path.html
+++ b/b2g/components/test/mochitest/test_filepicker_path.html
@@ -72,17 +72,16 @@ var testCases = [
   { pickedResult: { success: true,
                     result: {
                               type: 'text/plain',
                               blob: new File(['1234567890'],
                                              'test6.txt',
                                              { type: 'text/plain' })
                             }
                 },
-    todo: true,
     fileName: 'test6.txt'}
 ];
 
 var chromeJS = SimpleTest.getTestFileURL('filepicker_path_handler_chrome.js');
 var chromeScript = SpecialPowers.loadChromeScript(chromeJS);
 var activeTestCase;
 
 chromeScript.addMessageListener('pick-result-updated', handleMessage);
@@ -91,22 +90,18 @@ chromeScript.addMessageListener('file-pi
 // handle messages returned from chromeScript
 function handleMessage(data) {
   var fileInput = document.getElementById('fileInput');
   switch (data.type) {
     case 'pick-result-updated':
       fileInput.click();
       break;
     case 'file-picked-posted':
-      if (activeTestCase.todo) {
-        todo_is(fileInput.value, activeTestCase.fileName,
-                'DOMFile should be able to send through message.');
-      } else {
-        is(fileInput.value, activeTestCase.fileName);
-      }
+      is(fileInput.value, activeTestCase.fileName,
+         'DOMFile should be able to send through message.');
       processTestCase();
       break;
   }
 }
 
 function processTestCase() {
   if (!testCases.length) {
     SimpleTest.finish();
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="ca283b9db2b151d465cfd2e19346cf58fe89e413"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d5800c36b2d5822fc3fe1899b9280401de466e1e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="65fba428f8d76336b33ddd9e15900357953600ba">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="ca283b9db2b151d465cfd2e19346cf58fe89e413"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d5800c36b2d5822fc3fe1899b9280401de466e1e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "16395cc21812c26f896ad2fc9931acc8ca83a50c", 
+    "revision": "7bf976de32cf817ed4529ac875755ac6f6895b89", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cfc40f41bf417c2d242033fefd53b7aa3f3bf71c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="98ca8c55dbe2f21a8661d0eaa87f34d316c3bc98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3691614d0045f7968addce45d4140fb360c3ceaf"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -930,23 +930,28 @@ chatbox:-moz-full-screen-ancestor > .cha
 }
 
 /* Give this menupopup an arrow panel styling */
 #BMB_bookmarksPopup {
   -moz-appearance: none;
   -moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-arrow");
   background: transparent;
   border: none;
+  /* The popup inherits -moz-image-region from the button, must reset it */
+  -moz-image-region: auto;
+}
+
+%ifndef MOZ_WIDGET_GTK
+
+#BMB_bookmarksPopup {
   transform: scale(.7);
   opacity: 0;
   transition-property: transform, opacity;
   transition-duration: 0.15s;
   transition-timing-function: ease;
-  /* The popup inherits -moz-image-region from the button, must reset it */
-  -moz-image-region: auto;
 }
 
 #BMB_bookmarksPopup[animate="open"] {
   transform: none;
   opacity: 1.0;
 }
 
 #BMB_bookmarksPopup[arrowposition="after_start"] {
@@ -970,16 +975,17 @@ chatbox:-moz-full-screen-ancestor > .cha
   transform: scale(.7) skew(30deg, 20deg);
 }
 
 #BMB_bookmarksPopup[arrowposition="after_end"][animate="cancel"],
 #BMB_bookmarksPopup[arrowposition="before_start"][animate="cancel"] {
   transform: scale(.7) skew(-30deg, -20deg);
 }
 
+%endif
 
 /* Customize mode */
 #navigator-toolbox,
 #browser-bottombox,
 #content-deck {
   transition-property: margin-left, margin-right;
   transition-duration: 200ms;
   transition-timing-function: linear;
--- a/browser/devtools/sourceeditor/codemirror/css.js
+++ b/browser/devtools/sourceeditor/codemirror/css.js
@@ -399,17 +399,17 @@ CodeMirror.defineMode("css", function(co
     "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
     "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
     "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
     "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
     "font-stretch", "font-style", "font-synthesis", "font-variant",
     "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
     "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
     "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
-    "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
+    "grid-auto-rows", "grid-column", "grid-column-end",
     "grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
     "grid-template", "grid-template-areas", "grid-template-columns",
     "grid-template-rows", "hanging-punctuation", "height", "hyphens",
     "icon", "image-orientation", "image-rendering", "image-resolution",
     "inline-box-align", "justify-content", "left", "letter-spacing",
     "line-break", "line-height", "line-stacking", "line-stacking-ruby",
     "line-stacking-shift", "line-stacking-strategy", "list-style",
     "list-style-image", "list-style-position", "list-style-type", "margin",
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -48,19 +48,23 @@ endif
 ifdef _MSC_VER
 DEFINES += -D_MSC_VER=$(_MSC_VER)
 endif
 
 DEFINES += -DJAREXT=
 
 ifdef MOZ_ANGLE_RENDERER
 DEFINES += -DMOZ_ANGLE_RENDERER=$(MOZ_ANGLE_RENDERER)
+ifdef MOZ_D3DCOMPILER_VISTA_DLL
 DEFINES += -DMOZ_D3DCOMPILER_VISTA_DLL=$(MOZ_D3DCOMPILER_VISTA_DLL)
+endif
+ifdef MOZ_D3DCOMPILER_XP_DLL
 DEFINES += -DMOZ_D3DCOMPILER_XP_DLL=$(MOZ_D3DCOMPILER_XP_DLL)
 endif
+endif
 
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 # Set MSVC dlls version to package, if any.
 ifdef WIN32_REDIST_DIR
 DEFINES += -DMOZ_MSVC_REDIST=$(_MSC_VER)
 endif
 
--- a/chrome/src/nsChromeRegistryChrome.cpp
+++ b/chrome/src/nsChromeRegistryChrome.cpp
@@ -609,25 +609,25 @@ nsChromeRegistryChrome::kTableOps = {
   ClearEntry,
   PL_DHashFinalizeStub,
   InitEntry
 };
 
 nsChromeRegistryChrome::ProviderEntry*
 nsChromeRegistryChrome::nsProviderArray::GetProvider(const nsACString& aPreferred, MatchType aType)
 {
-  int32_t i = mArray.Count();
+  int32_t i = mArray.Length();
   if (!i)
     return nullptr;
 
   ProviderEntry* found = nullptr;  // Only set if we find a partial-match locale
   ProviderEntry* entry;
 
   while (i--) {
-    entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
+    entry = &mArray[i];
     if (aPreferred.Equals(entry->provider))
       return entry;
 
     if (aType != LOCALE)
       continue;
 
     if (LanguagesMatch(aPreferred, entry->provider)) {
       found = entry;
@@ -672,46 +672,29 @@ nsChromeRegistryChrome::nsProviderArray:
   ProviderEntry* provider = GetProvider(aProvider, EXACT);
 
   if (provider) {
     provider->baseURI = aBaseURL;
     return;
   }
 
   // no existing entries, add a new one
-  provider = new ProviderEntry(aProvider, aBaseURL);
-  if (!provider)
-    return; // It's safe to silently fail on OOM
-
-  mArray.AppendElement(provider);
+  mArray.AppendElement(ProviderEntry(aProvider, aBaseURL));
 }
 
 void
 nsChromeRegistryChrome::nsProviderArray::EnumerateToArray(nsTArray<nsCString> *a)
 {
-  int32_t i = mArray.Count();
+  int32_t i = mArray.Length();
   while (i--) {
-    ProviderEntry *entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
-    a->AppendElement(entry->provider);
+    a->AppendElement(mArray[i].provider);
   }
 }
 
 void
-nsChromeRegistryChrome::nsProviderArray::Clear()
-{
-  int32_t i = mArray.Count();
-  while (i--) {
-    ProviderEntry* entry = reinterpret_cast<ProviderEntry*>(mArray[i]);
-    delete entry;
-  }
-
-  mArray.Clear();
-}
-
-void
 nsChromeRegistryChrome::OverlayListEntry::AddURI(nsIURI* aURI)
 {
   int32_t i = mArray.Count();
   while (i--) {
     bool equals;
     if (NS_SUCCEEDED(aURI->Equals(mArray[i], &equals)) && equals)
       return;
   }
--- a/chrome/src/nsChromeRegistryChrome.h
+++ b/chrome/src/nsChromeRegistryChrome.h
@@ -3,17 +3,17 @@
  * 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 nsChromeRegistryChrome_h
 #define nsChromeRegistryChrome_h
 
 #include "nsCOMArray.h"
 #include "nsChromeRegistry.h"
-#include "nsVoidArray.h"
+#include "nsTArray.h"
 #include "mozilla/Move.h"
 
 namespace mozilla {
 namespace dom {
 class PContentParent;
 }
 }
 
@@ -80,37 +80,35 @@ class nsChromeRegistryChrome : public ns
     nsCOMPtr<nsIURI> baseURI;
   };
 
   class nsProviderArray
   {
    public:
     nsProviderArray() :
     mArray(1) { }
-    ~nsProviderArray()
-    { Clear(); }
+    ~nsProviderArray() { }
 
     // When looking up locales and skins, the "selected" locale is not always
     // available. This enum identifies what kind of match is desired/found.
     enum MatchType {
       EXACT = 0,
       LOCALE = 1, // "en-GB" is selected, we found "en-US"
       ANY = 2
     };
 
     nsIURI* GetBase(const nsACString& aPreferred, MatchType aType);
     const nsACString& GetSelected(const nsACString& aPreferred, MatchType aType);
     void    SetBase(const nsACString& aProvider, nsIURI* base);
     void    EnumerateToArray(nsTArray<nsCString> *a);
-    void    Clear();
 
    private:
     ProviderEntry* GetProvider(const nsACString& aPreferred, MatchType aType);
 
-    nsVoidArray mArray;
+    nsTArray<ProviderEntry> mArray;
   };
 
   struct PackageEntry : public PLDHashEntryHdr
   {
     PackageEntry(const nsACString& package)
     : package(package), flags(0) { }
     ~PackageEntry() { }
 
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -29,24 +29,27 @@
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/FileManager.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 
+class nsDOMMultipartFile;
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 
 class nsDOMFileBase : public nsIDOMFile,
                       public nsIXHRSendable,
                       public nsIMutable
 {
+  friend class nsDOMMultipartFile;
+
 public:
   typedef mozilla::dom::indexedDB::FileInfo FileInfo;
 
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType) = 0;
 
   virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
@@ -356,18 +359,19 @@ protected:
  */
 class nsDOMMemoryFile : public nsDOMFile
 {
 public:
   // Create as file
   nsDOMMemoryFile(void *aMemoryBuffer,
                   uint64_t aLength,
                   const nsAString& aName,
-                  const nsAString& aContentType)
-    : nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
+                  const nsAString& aContentType,
+                  uint64_t aLastModifiedDate)
+    : nsDOMFile(aName, aContentType, aLength, aLastModifiedDate),
       mDataOwner(new DataOwner(aMemoryBuffer, aLength))
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
   // Create as blob
   nsDOMMemoryFile(void *aMemoryBuffer,
                   uint64_t aLength,
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -1821,16 +1821,21 @@ protected:
     // Pointer to the root of our subtree.  Might be null.
     nsINode* mSubtreeRoot;
   };
 
   // Storage for more members that are usually not needed; allocated lazily.
   nsSlots* mSlots;
 };
 
+inline nsIDOMNode* GetAsDOMNode(nsINode* aNode)
+{
+  return aNode ? aNode->AsDOMNode() : nullptr;
+}
+
 // Useful inline function for getting a node given an nsIContent and an
 // nsIDocument.  Returns the first argument cast to nsINode if it is non-null,
 // otherwise returns the second (which may be null).  We use type variables
 // instead of nsIContent* and nsIDocument* because the actual types must be
 // known for the cast to work.
 template<class C, class D>
 inline nsINode* NODE_FROM(C& aContent, D& aDocument)
 {
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -22,36 +22,16 @@ using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS_INHERITED(nsDOMMultipartFile, nsDOMFile,
                             nsIJSNativeInitializer)
 
 NS_IMETHODIMP
 nsDOMMultipartFile::GetSize(uint64_t* aLength)
 {
-  if (mLength == UINT64_MAX) {
-    CheckedUint64 length = 0;
-  
-    uint32_t i;
-    uint32_t len = mBlobs.Length();
-    for (i = 0; i < len; i++) {
-      nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
-      uint64_t l = 0;
-  
-      nsresult rv = blob->GetSize(&l);
-      NS_ENSURE_SUCCESS(rv, rv);
-  
-      length += l;
-    }
-  
-    NS_ENSURE_TRUE(length.isValid(), NS_ERROR_FAILURE);
-
-    mLength = length.value();
-  }
-
   *aLength = mLength;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMMultipartFile::GetInternalStream(nsIInputStream** aStream)
 {
   nsresult rv;
@@ -209,16 +189,18 @@ nsDOMMultipartFile::InitBlob(JSContext* 
     mContentType = d.mType;
     nativeEOL = d.mEndings == EndingTypes::Native;
   }
 
   if (aArgc > 0) {
     return ParseBlobArrayArgument(aCx, aArgv[0], nativeEOL, aUnwrapFunc);
   }
 
+  SetLengthAndModifiedDate();
+
   return NS_OK;
 }
 
 nsresult
 nsDOMMultipartFile::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
                                            bool aNativeEOL,
                                            UnwrapFuncPtr aUnwrapFunc)
 {
@@ -274,19 +256,58 @@ nsDOMMultipartFile::ParseBlobArrayArgume
     JSString* str = JS::ToString(aCx, element);
     NS_ENSURE_TRUE(str, NS_ERROR_TYPE_ERR);
 
     nsresult rv = blobSet.AppendString(str, aNativeEOL, aCx);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mBlobs = blobSet.GetBlobs();
+
+  SetLengthAndModifiedDate();
+
   return NS_OK;
 }
 
+void
+nsDOMMultipartFile::SetLengthAndModifiedDate()
+{
+  MOZ_ASSERT(mLength == UINT64_MAX);
+  MOZ_ASSERT(mLastModificationDate == UINT64_MAX);
+
+  uint64_t totalLength = 0;
+
+  for (uint32_t index = 0, count = mBlobs.Length(); index < count; index++) {
+    nsCOMPtr<nsIDOMBlob>& blob = mBlobs[index];
+
+#ifdef DEBUG
+    {
+      // XXX This is only safe so long as all blob implementations in our tree
+      //     inherit nsDOMFileBase.
+      const auto* blobBase = static_cast<nsDOMFileBase*>(blob.get());
+
+      MOZ_ASSERT(!blobBase->IsSizeUnknown());
+      MOZ_ASSERT(!blobBase->IsDateUnknown());
+    }
+#endif
+
+    uint64_t subBlobLength;
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&subBlobLength)));
+
+    MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
+    totalLength += subBlobLength;
+  }
+
+  mLength = totalLength;
+
+  if (mIsFile) {
+    mLastModificationDate = PR_Now();
+  }
+}
+
 NS_IMETHODIMP
 nsDOMMultipartFile::GetMozFullPathInternal(nsAString &aFilename)
 {
   if (!mIsFromNsiFile || mBlobs.Length() == 0) {
     return nsDOMFile::GetMozFullPathInternal(aFilename);
   }
 
   nsIDOMBlob* blob = mBlobs.ElementAt(0).get();
@@ -369,28 +390,41 @@ nsDOMMultipartFile::InitChromeFile(JSCon
     rv = file->IsDirectory(&isDir);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
 
     if (mName.IsEmpty()) {
       file->GetLeafName(mName);
     }
 
-    blob = new nsDOMFileFile(file);
+    nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
+
+    // Pre-cache size.
+    uint64_t unused;
+    rv = domFile->GetSize(&unused);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Pre-cache modified date.
+    rv = domFile->GetMozLastModifiedDate(&unused);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    blob = domFile.forget();
   }
 
   // XXXkhuey this is terrible
   if (mContentType.IsEmpty()) {
     blob->GetType(mContentType);
   }
 
   BlobSet blobSet;
   blobSet.AppendBlob(blob);
   mBlobs = blobSet.GetBlobs();
 
+  SetLengthAndModifiedDate();
+
   return NS_OK;
 }
 
 nsresult
 nsDOMMultipartFile::InitFile(JSContext* aCx,
                              uint32_t aArgc,
                              JS::Value* aArgv)
 {
--- a/content/base/src/nsDOMBlobBuilder.h
+++ b/content/base/src/nsDOMBlobBuilder.h
@@ -27,25 +27,27 @@ public:
   // Create as a file
   nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
                      const nsAString& aName,
                      const nsAString& aContentType)
     : nsDOMFile(aName, aContentType, UINT64_MAX),
       mBlobs(aBlobs),
       mIsFromNsiFile(false)
   {
+    SetLengthAndModifiedDate();
   }
 
   // Create as a blob
   nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs,
                      const nsAString& aContentType)
     : nsDOMFile(aContentType, UINT64_MAX),
       mBlobs(aBlobs),
       mIsFromNsiFile(false)
   {
+    SetLengthAndModifiedDate();
   }
 
   // Create as a file to be later initialized
   nsDOMMultipartFile(const nsAString& aName)
     : nsDOMFile(aName, EmptyString(), UINT64_MAX),
       mIsFromNsiFile(false)
   {
   }
@@ -104,16 +106,18 @@ public:
   GetSubBlobs() const MOZ_OVERRIDE { return &mBlobs; }
 
   NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
 
 protected:
   nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
                                   bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
 
+  void SetLengthAndModifiedDate();
+
   nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
   bool mIsFromNsiFile;
 };
 
 class BlobSet {
 public:
   BlobSet()
     : mData(nullptr), mDataLen(0), mDataBufferLen(0)
@@ -165,17 +169,17 @@ protected:
   }
 
   void Flush() {
     if (mData) {
       // If we have some data, create a blob for it
       // and put it on the stack
 
       nsCOMPtr<nsIDOMBlob> blob =
-        new nsDOMMemoryFile(mData, mDataLen, EmptyString(), EmptyString());
+        new nsDOMMemoryFile(mData, mDataLen, EmptyString());
       mBlobs.AppendElement(blob);
       mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
       mDataLen = 0;
       mDataBufferLen = 0;
     }
   }
 
   nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -586,17 +586,17 @@ HTMLCanvasElement::MozGetAsFileImpl(cons
 
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
   if (cx) {
     JS_updateMallocCounter(cx, imgSize);
   }
 
   // The DOMFile takes ownership of the buffer
   nsRefPtr<nsDOMMemoryFile> file =
-    new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type);
+    new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type, PR_Now());
 
   file.forget(aResult);
   return NS_OK;
 }
 
 nsresult
 HTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
                                     nsICanvasRenderingContextInternal **aContext)
--- a/content/html/content/src/HTMLInputElement.h
+++ b/content/html/content/src/HTMLInputElement.h
@@ -1316,17 +1316,17 @@ private:
   }
 
   /**
    * Returns true if setRangeText can be called on element
    */
   bool SupportsSetRangeText() const {
     return mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_SEARCH ||
            mType == NS_FORM_INPUT_URL || mType == NS_FORM_INPUT_TEL ||
-           mType == NS_FORM_INPUT_PASSWORD;
+           mType == NS_FORM_INPUT_PASSWORD || mType == NS_FORM_INPUT_NUMBER;
   }
 
   static bool MayFireChangeOnBlur(uint8_t aType) {
     return IsSingleLineTextControl(false, aType) ||
            aType == NS_FORM_INPUT_RANGE ||
            aType == NS_FORM_INPUT_NUMBER;
   }
 
--- a/content/html/content/test/forms/test_set_range_text.html
+++ b/content/html/content/test/forms/test_set_range_text.html
@@ -15,16 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content">
 
 <!-- "SetRangeText() supported types"-->
 <input type="text" id="input_text"></input>
 <input type="search" id="input_search"></input>
 <input type="url" id="input_url"></input>
 <input type="tel" id="input_tel"></input>
 <input type="password" id="input_password"></input>
+<input type="number" id="input_number"></input>
 <textarea id="input_textarea"></textarea>
 
 <!-- "SetRangeText() non-supported types" -->
 <input type="button" id="input_button"></input>
 <input type="submit" id="input_submit"></input>
 <input type="image" id="input_image"></input>
 <input type="reset" id="input_reset"></input>
 <input type="radio" id="input_radio"></input>
@@ -34,17 +35,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <input type="email" id="input_email"></input>
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
   /** Tests for Bug 850364 && Bug 918940**/
 
-  var SupportedTypes = ["text", "search", "url", "tel", "password", "textarea"];
+  var SupportedTypes = ["text", "search", "url", "tel", "password", "textarea", "number"];
   var NonSupportedTypes = ["button", "submit", "image", "reset", "radio",
                            "checkbox", "range", "file", "email"];
 
   SimpleTest.waitForExplicitFinish();
 
   function TestInputs() {
 
     var opThrows, elem, i, msg;
@@ -87,154 +88,154 @@ https://bugzilla.mozilla.org/show_bug.cg
         }
       }, false);
 
       elem.addEventListener("input", function (aEvent) {
         ok(false, "input event should NOT be fired for " + + aEvent.target.id);
       }, false);
 
       var test = " setRange(replacement), shrink";
-      elem.value = "0123456789ABCDEF";
+      elem.value = "0123456789123456";
       elem.setSelectionRange(1, 6);
-      elem.setRangeText("xyz");
-      is(elem.value, "0xyz6789ABCDEF", msg + test);
+      elem.setRangeText("999");
+      is(elem.value, "09996789123456", msg + test);
       is(elem.selectionStart, 1, msg + test);
       is(elem.selectionEnd, 4, msg + test);
-      elem.setRangeText("mnk");
-      is(elem.value, "0mnk6789ABCDEF", msg + test);
+      elem.setRangeText("222");
+      is(elem.value, "02226789123456", msg + test);
       expectedNumOfSelectCalls += 3;
 
       test = " setRange(replacement), expand";
-      elem.value = "0123456789ABCDEF";
+      elem.value = "0123456789123456";
       elem.setSelectionRange(1, 2);
-      elem.setRangeText("xyz");
-      is(elem.value, "0xyz23456789ABCDEF", msg + test);
+      elem.setRangeText("999");
+      is(elem.value, "099923456789123456", msg + test);
       is(elem.selectionStart, 1, msg + test);
       is(elem.selectionEnd, 4, msg + test);
-      elem.setRangeText("mnk");
-      is(elem.value, "0mnk23456789ABCDEF", msg + test);
+      elem.setRangeText("222");
+      is(elem.value, "022223456789123456", msg + test);
       expectedNumOfSelectCalls += 3;
 
       test = " setRange(replacement) pure insertion at start";
-      elem.value = "0123456789ABCDEF";
+      elem.value = "0123456789123456";
       elem.setSelectionRange(0, 0);
-      elem.setRangeText("xyz");
-      is(elem.value, "xyz0123456789ABCDEF", msg + test);
+      elem.setRangeText("999");
+      is(elem.value, "9990123456789123456", msg + test);
       is(elem.selectionStart, 0, msg + test);
       is(elem.selectionEnd, 0, msg + test);
-      elem.setRangeText("mnk");
-      is(elem.value, "mnkxyz0123456789ABCDEF", msg + test);
+      elem.setRangeText("222");
+      is(elem.value, "2229990123456789123456", msg + test);
       expectedNumOfSelectCalls += 3;
 
       test = " setRange(replacement) pure insertion in the middle";
-      elem.value = "0123456789ABCDEF";
+      elem.value = "0123456789123456";
       elem.setSelectionRange(4, 4);
-      elem.setRangeText("xyz");
-      is(elem.value, "0123xyz456789ABCDEF", msg + test);
+      elem.setRangeText("999");
+      is(elem.value, "0123999456789123456", msg + test);
       is(elem.selectionStart, 4, msg + test);
       is(elem.selectionEnd, 4, msg + test);
-      elem.setRangeText("mnk");
-      is(elem.value, "0123mnkxyz456789ABCDEF", msg + test);
+      elem.setRangeText("222");
+      is(elem.value, "0123222999456789123456", msg + test);
       expectedNumOfSelectCalls += 3;
 
       test = " setRange(replacement) pure insertion at the end";
-      elem.value = "0123456789ABCDEF";
+      elem.value = "1123456789123456";
       elem.setSelectionRange(16, 16);
-      elem.setRangeText("xyz");
-      is(elem.value, "0123456789ABCDEFxyz", msg + test);
+      elem.setRangeText("999");
+      is(elem.value, "1123456789123456999", msg + test);
       is(elem.selectionStart, 16, msg + test);
       is(elem.selectionEnd, 16, msg + test);
-      elem.setRangeText("mnk");
-      is(elem.value, "0123456789ABCDEFmnkxyz", msg + test);
+      elem.setRangeText("222");
+      is(elem.value, "1123456789123456222999", msg + test);
       expectedNumOfSelectCalls += 3;
 
       //test SetRange(replacement, start, end, mode) with start > end
       try {
         elem.setRangeText("abc", 20, 4);
       } catch (ex) {
         opThrows = (ex.name == "IndexSizeError" && ex.code == DOMException.INDEX_SIZE_ERR);
       }
       is(opThrows, true, msg + " should throw IndexSizeError");
 
       //test SelectionMode 'select'
-      elem.value = "0123456789ABCDEF";
-      elem.setRangeText("xyz", 4, 9, "select");
-      is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\"");
+      elem.value = "1023456789123456";
+      elem.setRangeText("999", 4, 9, "select");
+      is(elem.value, "10239999123456", msg + ".value == \"10239999123456\"");
       is(elem.selectionStart, 4, msg + ".selectionStart == 4, with \"select\"");
       is(elem.selectionEnd, 7, msg + ".selectionEnd == 7, with \"select\"");
       expectedNumOfSelectCalls += 1;
 
-      elem.setRangeText("pqm", 6, 25, "select");
-      is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\"");
+      elem.setRangeText("888", 6, 25, "select");
+      is(elem.value, "102399888", msg + ".value == \"102399888\"");
       is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"select\"");
       is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"select\"");
       expectedNumOfSelectCalls += 1;
 
       //test SelectionMode 'start'
-      elem.value = "0123456789ABCDEF";
-      elem.setRangeText("xyz", 4, 9, "start");
-      is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\"");
+      elem.value = "0123456789123456";
+      elem.setRangeText("999", 4, 9, "start");
+      is(elem.value, "01239999123456", msg + ".value == \"01239999123456\"");
       is(elem.selectionStart, 4, msg + ".selectionStart == 4, with \"start\"");
       is(elem.selectionEnd, 4, msg + ".selectionEnd == 4, with \"start\"");
       expectedNumOfSelectCalls += 1;
 
-      elem.setRangeText("pqm", 6, 25, "start");
-      is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\"");
+      elem.setRangeText("888", 6, 25, "start");
+      is(elem.value, "012399888", msg + ".value == \"012399888\"");
       is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"start\"");
       is(elem.selectionEnd, 6, msg + ".selectionEnd == 6, with \"start\"");
       expectedNumOfSelectCalls += 1;
 
       //test SelectionMode 'end'
-      elem.value = "0123456789ABCDEF";
-      elem.setRangeText("xyz", 4, 9, "end");
-      is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\"");
+      elem.value = "1023456789123456";
+      elem.setRangeText("999", 4, 9, "end");
+      is(elem.value, "10239999123456", msg + ".value == \"10239999123456\"");
       is(elem.selectionStart, 7, msg + ".selectionStart == 7, with \"end\"");
       is(elem.selectionEnd, 7, msg + ".selectionEnd == 7, with \"end\"");
       expectedNumOfSelectCalls += 1;
 
-      elem.setRangeText("pqm", 6, 25, "end");
-      is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\"");
+      elem.setRangeText("888", 6, 25, "end");
+      is(elem.value, "102399888", msg + ".value == \"102399888\"");
       is(elem.selectionStart, 9, msg + ".selectionStart == 9, with \"end\"");
       is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"end\"");
       expectedNumOfSelectCalls += 1;
 
       //test SelectionMode 'preserve' (default)
 
       //subcase: selection{Start|End} > end
       elem.value = "0123456789";
       elem.setSelectionRange(6, 9);
-      elem.setRangeText("Z", 1, 2, "preserve");
-      is(elem.value, "0Z23456789", msg + ".value == \"0Z23456789\"");
+      elem.setRangeText("7", 1, 2, "preserve");
+      is(elem.value, "0723456789", msg + ".value == \"0723456789\"");
       is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"preserve\"");
       is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"preserve\"");
       expectedNumOfSelectCalls += 2;
 
       //subcase: selection{Start|End} < end
       elem.value = "0123456789";
       elem.setSelectionRange(4, 5);
-      elem.setRangeText("QRST", 2, 9, "preserve");
-      is(elem.value, "01QRST9", msg + ".value == \"01QRST9\"");
+      elem.setRangeText("3456", 2, 9, "preserve");
+      is(elem.value, "0134569", msg + ".value == \"0134569\"");
       is(elem.selectionStart, 2, msg + ".selectionStart == 2, with \"preserve\"");
       is(elem.selectionEnd, 6, msg + ".selectionEnd == 6, with \"preserve\"");
       expectedNumOfSelectCalls += 2;
 
       //subcase: selectionStart > end, selectionEnd < end
       elem.value = "0123456789";
       elem.setSelectionRange(8, 4);
-      elem.setRangeText("QRST", 1, 5);
-      is(elem.value, "0QRST56789", msg + ".value == \"0QRST56789\"");
+      elem.setRangeText("3456", 1, 5);
+      is(elem.value, "0345656789", msg + ".value == \"0345656789\"");
       is(elem.selectionStart, 1, msg + ".selectionStart == 1, with \"default\"");
       is(elem.selectionEnd, 5, msg + ".selectionEnd == 5, with \"default\"");
       expectedNumOfSelectCalls += 2;
 
       //subcase: selectionStart < end, selectionEnd > end
       elem.value = "0123456789";
       elem.setSelectionRange(4, 9);
-      elem.setRangeText("QRST", 2, 6);
-      is(elem.value, "01QRST6789", msg + ".value == \"01QRST6789\"");
+      elem.setRangeText("3456", 2, 6);
+      is(elem.value, "0134566789", msg + ".value == \"0134566789\"");
       is(elem.selectionStart, 2, msg + ".selectionStart == 2, with \"default\"");
       is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"default\"");
       expectedNumOfSelectCalls += 2;
     }
   }
 
   addLoadEvent(TestInputs);
 
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -416,17 +416,17 @@ skip-if = buildapp == 'b2g' # b2g(bug 89
 [test_mediarecorder_record_immediate_stop.html]
 [test_mediarecorder_record_session.html]
 [test_mediarecorder_record_startstopstart.html]
 [test_mediarecorder_getencodeddata.html]
 [test_mediarecorder_unsupported_src.html]
 [test_mediarecorder_record_gum_video_timeslice.html]
 skip-if = buildapp == 'b2g' || (toolkit == 'android') # mimetype check, bug 969289
 [test_playback.html]
-skip-if = buildapp == 'b2g' # b2g(Test timed out, bug 668973?) b2g-debug(Test timed out, bug 668973?) b2g-desktop(Test timed out, bug 668973?)
+skip-if = buildapp == 'b2g' || toolkit == 'android' # Disabled on Android & B2G due to bug 668973
 [test_seekLies.html]
 [test_media_sniffer.html]
 [test_streams_srcObject.html]
 [test_reset_src.html]
 [test_streams_autoplay.html]
 [test_streams_element_capture.html]
 [test_streams_element_capture_reset.html]
 skip-if = buildapp == 'b2g' # b2g(bug 901102) b2g-debug(bug 901102) b2g-desktop(bug 901102)
@@ -463,17 +463,18 @@ skip-if = buildapp == 'b2g'
 # runs, like bug 918417, bug 920827, bug 923996, bug 928225, bug 929521
 # bug 930982, bug 932193. Worst-case but quite likely, it causes random
 # crashes and failures in other tests which run after it. Don't even think
 # about reenabling it on any platform unless you *know* that you have fixed
 # that. Then don't think about reenabling it on Windows until you know that
 # you have fixed the timeouts of bug 832768, bug 814533, bug 840742
 
 [test_play_twice.html]
-skip-if = (appname == "seamonkey") || (toolkit == 'gonk') # Seamonkey: Bug 598252, B2G: Bug 982100
+# Seamonkey: Bug 598252, B2G: Bug 982100, Android: Bug 758476, bug 981086
+skip-if = appname == "seamonkey" || toolkit == 'gonk' || toolkit == 'android'
 
 [test_buffered.html]
 skip-if = toolkit == 'android' || os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682, b2g(assertion failures)
 [test_bug465498.html]
 skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682
 [test_bug493187.html]
 skip-if = os == "win" || (buildapp=='b2g'&&debug) || (toolkit == 'gonk' && !debug) # See bug 707777, #b2g-emulator-debug - process crash
 [test_media_selection.html]
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -895,27 +895,37 @@ Console::Method(JSContext* aCx, MethodNa
     callData->mReifiedStack.construct();
     nsresult rv = ReifyStack(stack, callData->mReifiedStack.ref());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
   }
 
   // Monotonic timer for 'time' and 'timeEnd'
-  if ((aMethodName == MethodTime || aMethodName == MethodTimeEnd) && mWindow) {
-    nsGlobalWindow *win = static_cast<nsGlobalWindow*>(mWindow.get());
-    MOZ_ASSERT(win);
+  if ((aMethodName == MethodTime || aMethodName == MethodTimeEnd)) {
+    if (mWindow) {
+      nsGlobalWindow *win = static_cast<nsGlobalWindow*>(mWindow.get());
+      MOZ_ASSERT(win);
+
+      ErrorResult rv;
+      nsRefPtr<nsPerformance> performance = win->GetPerformance(rv);
+      if (rv.Failed()) {
+        return;
+      }
 
-    ErrorResult rv;
-    nsRefPtr<nsPerformance> performance = win->GetPerformance(rv);
-    if (rv.Failed()) {
-      return;
+      callData->mMonotonicTimer = performance->Now();
+    } else {
+      WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+      MOZ_ASSERT(workerPrivate);
+
+      TimeDuration duration =
+        mozilla::TimeStamp::Now() - workerPrivate->CreationTimeStamp();
+
+      callData->mMonotonicTimer = duration.ToMilliseconds();
     }
-
-    callData->mMonotonicTimer = performance->Now();
   }
 
   // The operation is completed. RAII class has to be disabled.
   raii.Finished();
 
   if (!NS_IsMainThread()) {
     // Here we are in a worker thread. The ConsoleCallData has to been removed
     // from the list and it will be deleted by the ConsoleCallDataRunnable or
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -572,16 +572,33 @@ nsDOMWindowUtils::GetResolution(float* a
     *aXResolution = presShell->GetXResolution();
     *aYResolution = presShell->GetYResolution();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GetIsHistoryRestored(bool* aIsHistoryRestored) {
+  if (!nsContentUtils::IsCallerChrome()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  nsIPresShell* presShell = GetPresShell();
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
+  }
+
+  const nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
+  *aIsHistoryRestored = sf && sf->DidHistoryRestore();
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsIPresShell* presShell = GetPresShell();
   if (presShell) {
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -43,17 +43,17 @@ interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 interface nsITranslationNodeList;
 
-[scriptable, uuid(d68ea9fa-b1ea-4744-a78e-bb0e6ef95f55)]
+[scriptable, uuid(8489681a-7407-457e-b889-53d1ae999b30)]
 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.
@@ -226,16 +226,25 @@ interface nsIDOMWindowUtils : nsISupport
    *
    * The caller of this method must have chrome privileges.
    */
   void setResolution(in float aXResolution, in float aYResolution);
 
   void getResolution(out float aXResolution, out float aYResolution);
 
   /**
+   * Whether the current window has been restored from session history.
+   * This gives a way to check whether the provided resolution and scroll
+   * position are default values or restored from a previous session.
+   *
+   * Can only be accessed with chrome privileges.
+   */
+  readonly attribute boolean isHistoryRestored;
+
+  /**
    * Whether the next paint should be flagged as the first paint for a document.
    * This gives a way to track the next paint that occurs after the flag is
    * set. The flag gets cleared after the next paint.
    *
    * Can only be accessed with chrome privileges.
    */
   attribute boolean isFirstPaint;
 
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1816,20 +1816,25 @@ BlobParent*
 BlobParent::Create(ContentParent* aManager,
                    const ParentBlobConstructorParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aManager);
 
   const ChildBlobConstructorParams& blobParams = aParams.blobParams();
 
+  MOZ_ASSERT(blobParams.type() !=
+             ChildBlobConstructorParams::TMysteryBlobConstructorParams);
+
   switch (blobParams.type()) {
+    case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
+      return nullptr;
+
     case ChildBlobConstructorParams::TNormalBlobConstructorParams:
     case ChildBlobConstructorParams::TFileBlobConstructorParams:
-    case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
       return new BlobParent(aManager, aParams);
 
     case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
       const SlicedBlobConstructorParams& params =
         blobParams.get_SlicedBlobConstructorParams();
 
       auto* actor =
         const_cast<BlobParent*>(
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -871,110 +871,76 @@ ContentChild::GetOrCreateActorForBlob(ns
   if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
     BlobChild* actor =
       static_cast<BlobChild*>(
         static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
     MOZ_ASSERT(actor);
     return actor;
   }
 
-  // XXX This is only safe so long as all blob implementations in our tree
-  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
-  //     a real interface or something.
-  const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
-
-  // We often pass blobs that are multipart but that only contain one sub-blob
-  // (WebActivities does this a bunch). Unwrap to reduce the number of actors
-  // that we have to maintain.
-  const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
-  if (subBlobs && subBlobs->Length() == 1) {
-    const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
-    MOZ_ASSERT(subBlob);
-
-    // We can only take this shortcut if the multipart and the sub-blob are both
-    // Blob objects or both File objects.
-    nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
-    nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
-    if (!multipartBlobAsFile == !subBlobAsFile) {
-      // The wrapping was unnecessary, see if we can simply pass an existing
-      // remote blob.
-      if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(subBlob)) {
-        BlobChild* actor =
-          static_cast<BlobChild*>(
-            static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
-        MOZ_ASSERT(actor);
-        return actor;
-      }
-
-      // No need to add a reference here since the original blob must have a
-      // strong reference in the caller and it must also have a strong reference
-      // to this sub-blob.
-      aBlob = subBlob;
-      blob = static_cast<nsDOMFileBase*>(aBlob);
-      subBlobs = blob->GetSubBlobs();
-    }
-  }
-
   // All blobs shared between processes must be immutable.
   nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
   if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
     NS_WARNING("Failed to make blob immutable!");
     return nullptr;
   }
 
+#ifdef DEBUG
+  {
+    // XXX This is only safe so long as all blob implementations in our tree
+    //     inherit nsDOMFileBase. If that ever changes then this will need to
+    //     grow a real interface or something.
+    const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
+
+    MOZ_ASSERT(!blob->IsSizeUnknown());
+    MOZ_ASSERT(!blob->IsDateUnknown());
+  }
+#endif
+
   ParentBlobConstructorParams params;
 
-  if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
-    // We don't want to call GetSize or GetLastModifiedDate
-    // yet since that may stat a file on the main thread
-    // here. Instead we'll learn the size lazily from the
-    // other process.
-    params.blobParams() = MysteryBlobConstructorParams();
-    params.optionalInputStreamParams() = void_t();
-  }
-  else {
-    nsString contentType;
-    nsresult rv = aBlob->GetType(contentType);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+  nsString contentType;
+  nsresult rv = aBlob->GetType(contentType);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  uint64_t length;
+  rv = aBlob->GetSize(&length);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  nsCOMPtr<nsIInputStream> stream;
+  rv = aBlob->GetInternalStream(getter_AddRefs(stream));
+  NS_ENSURE_SUCCESS(rv, nullptr);
 
-    uint64_t length;
-    rv = aBlob->GetSize(&length);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+  InputStreamParams inputStreamParams;
+  nsTArray<mozilla::ipc::FileDescriptor> fds;
+  SerializeInputStream(stream, inputStreamParams, fds);
+
+  MOZ_ASSERT(fds.IsEmpty());
 
-    nsCOMPtr<nsIInputStream> stream;
-    rv = aBlob->GetInternalStream(getter_AddRefs(stream));
+  params.optionalInputStreamParams() = inputStreamParams;
+
+  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
+  if (file) {
+    FileBlobConstructorParams fileParams;
+
+    rv = file->GetName(fileParams.name());
     NS_ENSURE_SUCCESS(rv, nullptr);
 
-    InputStreamParams inputStreamParams;
-    nsTArray<mozilla::ipc::FileDescriptor> fds;
-    SerializeInputStream(stream, inputStreamParams, fds);
-    MOZ_ASSERT(fds.IsEmpty());
-
-    params.optionalInputStreamParams() = inputStreamParams;
+    rv = file->GetMozLastModifiedDate(&fileParams.modDate());
+    NS_ENSURE_SUCCESS(rv, nullptr);
 
-    nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
-    if (file) {
-      FileBlobConstructorParams fileParams;
-
-      rv = file->GetName(fileParams.name());
-      NS_ENSURE_SUCCESS(rv, nullptr);
+    fileParams.contentType() = contentType;
+    fileParams.length() = length;
 
-      rv = file->GetMozLastModifiedDate(&fileParams.modDate());
-      NS_ENSURE_SUCCESS(rv, nullptr);
-
-      fileParams.contentType() = contentType;
-      fileParams.length() = length;
-
-      params.blobParams() = fileParams;
-    } else {
-      NormalBlobConstructorParams blobParams;
-      blobParams.contentType() = contentType;
-      blobParams.length() = length;
-      params.blobParams() = blobParams;
-    }
+    params.blobParams() = fileParams;
+  } else {
+    NormalBlobConstructorParams blobParams;
+    blobParams.contentType() = contentType;
+    blobParams.length() = length;
+    params.blobParams() = blobParams;
   }
 
   BlobChild* actor = BlobChild::Create(this, aBlob);
   NS_ENSURE_TRUE(actor, nullptr);
 
   return SendPBlobConstructor(actor, params) ? actor : nullptr;
 }
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2365,63 +2365,28 @@ ContentParent::GetOrCreateActorForBlob(n
     if (BlobParent* actor = static_cast<BlobParent*>(
           static_cast<PBlobParent*>(remoteBlob->GetPBlob()))) {
       if (static_cast<ContentParent*>(actor->Manager()) == this) {
         return actor;
       }
     }
   }
 
-  // XXX This is only safe so long as all blob implementations in our tree
-  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
-  //     a real interface or something.
-  const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
-
-  // We often pass blobs that are multipart but that only contain one sub-blob
-  // (WebActivities does this a bunch). Unwrap to reduce the number of actors
-  // that we have to maintain.
-  const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
-  if (subBlobs && subBlobs->Length() == 1) {
-    const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
-    MOZ_ASSERT(subBlob);
-
-    // We can only take this shortcut if the multipart and the sub-blob are both
-    // Blob objects or both File objects.
-    nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
-    nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
-    if (!multipartBlobAsFile == !subBlobAsFile) {
-      // The wrapping might have been unnecessary, see if we can simply pass an
-      // existing remote blob for this ContentParent.
-      if (nsCOMPtr<nsIRemoteBlob> remoteSubBlob = do_QueryInterface(subBlob)) {
-        BlobParent* actor =
-          static_cast<BlobParent*>(
-            static_cast<PBlobParent*>(remoteSubBlob->GetPBlob()));
-        MOZ_ASSERT(actor);
-
-        if (static_cast<ContentParent*>(actor->Manager()) == this) {
-          return actor;
-        }
-      }
-
-      // No need to add a reference here since the original blob must have a
-      // strong reference in the caller and it must also have a strong reference
-      // to this sub-blob.
-      aBlob = subBlob;
-      blob = static_cast<nsDOMFileBase*>(aBlob);
-      subBlobs = blob->GetSubBlobs();
-    }
-  }
-
   // All blobs shared between processes must be immutable.
   nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
   if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
     NS_WARNING("Failed to make blob immutable!");
     return nullptr;
   }
 
+  // XXX This is only safe so long as all blob implementations in our tree
+  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
+  //     a real interface or something.
+  const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
+
   ChildBlobConstructorParams params;
 
   if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
     // We don't want to call GetSize or GetLastModifiedDate
     // yet since that may stat a file on the main thread
     // here. Instead we'll learn the size lazily from the
     // other process.
     params = MysteryBlobConstructorParams();
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -191,17 +191,17 @@ TabChildBase::HandlePossibleViewportChan
   }
 
   nsCOMPtr<nsIDocument> document(GetDocument());
   nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
 
   nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
   uint32_t presShellId;
   mozilla::layers::FrameMetrics::ViewID viewId;
-  bool scrollIdentifiersValid = APZCCallbackHelper::GetScrollIdentifiers(
+  bool scrollIdentifiersValid = APZCCallbackHelper::GetOrCreateScrollIdentifiers(
         document->GetDocumentElement(), &presShellId, &viewId);
   if (scrollIdentifiersValid) {
     ZoomConstraints constraints(
       viewportInfo.IsZoomAllowed(),
       viewportInfo.IsDoubleTapZoomAllowed(),
       viewportInfo.GetMinZoom(),
       viewportInfo.GetMaxZoom());
     DoUpdateZoomConstraints(presShellId,
@@ -721,18 +721,18 @@ TabChild::Observe(nsISupports *aSubject,
 {
   if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
     nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
     if (tabChild == this) {
       nsCOMPtr<nsIDocument> doc(GetDocument());
       uint32_t presShellId;
       ViewID viewId;
-      if (APZCCallbackHelper::GetScrollIdentifiers(doc->GetDocumentElement(),
-                                                    &presShellId, &viewId)) {
+      if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(doc->GetDocumentElement(),
+                                                           &presShellId, &viewId)) {
         CSSRect rect;
         sscanf(NS_ConvertUTF16toUTF8(aData).get(),
                "{\"x\":%f,\"y\":%f,\"w\":%f,\"h\":%f}",
                &rect.x, &rect.y, &rect.width, &rect.height);
         SendZoomToRect(presShellId, viewId, rect);
       }
     }
   } else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -20,16 +20,20 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 
 XPCOMUtils.defineLazyServiceGetter(this, "powerManagerService",
                                    "@mozilla.org/power/powermanagerservice;1",
                                    "nsIPowerManagerService");
 
+XPCOMUtils.defineLazyServiceGetter(this, "appsService",
+                                   "@mozilla.org/AppsService;1",
+                                   "nsIAppsService");
+
 // Limit the number of pending messages for a given page.
 let kMaxPendingMessages;
 try {
   kMaxPendingMessages =
     Services.prefs.getIntPref("dom.messages.maxPendingMessages");
 } catch(e) {
   // getIntPref throws when the pref is not set.
   kMaxPendingMessages = 5;
@@ -78,16 +82,17 @@ function SystemMessageInternal() {
 
   this._cpuWakeLocks = {};
 
   this._configurators = {};
 
   Services.obs.addObserver(this, "xpcom-shutdown", false);
   Services.obs.addObserver(this, "webapps-registry-start", false);
   Services.obs.addObserver(this, "webapps-registry-ready", false);
+  Services.obs.addObserver(this, "webapps-clear-data", false);
   kMessages.forEach(function(aMsg) {
     ppmm.addMessageListener(aMsg, this);
   }, this);
 
   Services.obs.notifyObservers(this, "system-message-internal-ready", null);
 }
 
 SystemMessageInternal.prototype = {
@@ -494,16 +499,17 @@ SystemMessageInternal.prototype = {
     switch (aTopic) {
       case "xpcom-shutdown":
         kMessages.forEach(function(aMsg) {
           ppmm.removeMessageListener(aMsg, this);
         }, this);
         Services.obs.removeObserver(this, "xpcom-shutdown");
         Services.obs.removeObserver(this, "webapps-registry-start");
         Services.obs.removeObserver(this, "webapps-registry-ready");
+        Services.obs.removeObserver(this, "webapps-clear-data");
         ppmm = null;
         this._pages = null;
         this._bufferedSysMsgs = null;
         break;
       case "webapps-registry-start":
         this._webappsRegistryReady = false;
         break;
       case "webapps-registry-ready":
@@ -519,16 +525,45 @@ SystemMessageInternal.prototype = {
               break;
             case "broadcast":
               this.broadcastMessage(aSysMsg.type, aSysMsg.msg, aSysMsg.extra);
               break;
           }
         }, this);
         this._bufferedSysMsgs.length = 0;
         break;
+      case "webapps-clear-data":
+        let params =
+          aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
+        if (!params) {
+          debug("Error updating registered pages for an uninstalled app.");
+          return;
+        }
+
+        // Only update registered pages for apps.
+        if (params.browserOnly) {
+          return;
+        }
+
+        let manifestURL = appsService.getManifestURLByLocalId(params.appId);
+        if (!manifestURL) {
+          debug("Error updating registered pages for an uninstalled app.");
+          return;
+        }
+
+        for (let i = this._pages.length - 1; i >= 0; i--) {
+          let page = this._pages[i];
+          if (page.manifestURL === manifestURL) {
+            this._pages.splice(i, 1);
+            debug("Remove " + page.pageURL + " @ " + page.manifestURL +
+                  " from registered pages due to app uninstallation.");
+          }
+        }
+        debug("Finish updating registered pages for an uninstalled app.");
+        break;
     }
   },
 
   _queueMessage: function(aPage, aMessage, aMessageID) {
     // Queue the message for this page because we've never known if an app is
     // opened or not. We'll clean it up when the app has already received it.
     aPage.pendingMessages.push({ msg: aMessage, msgID: aMessageID });
     if (aPage.pendingMessages.length > kMaxPendingMessages) {
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -834,17 +834,17 @@ NPP_New(NPMIMEType pluginType, NPP insta
   instanceData->backBuffer = nullptr;
   instanceData->mouseUpEventCount = 0;
   instanceData->bugMode = -1;
   instance->pdata = instanceData;
 
   TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass);
   if (!scriptableObject) {
     printf("NPN_CreateObject failed to create an object, can't create a plugin instance\n");
-    free(instanceData);
+    delete instanceData;
     return NPERR_GENERIC_ERROR;
   }
   scriptableObject->npp = instance;
   scriptableObject->drawMode = DM_DEFAULT;
   scriptableObject->drawColor = 0;
   instanceData->scriptableObject = scriptableObject;
 
   instanceData->instanceCountWatchGeneration = sCurrentInstanceCountWatchGeneration;
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1627,17 +1627,19 @@ WorkerMessenger.prototype = {
           libcutils.property_get("ro.moz.ril.simstate_extra_field", "false") === "true",
         extraUint2ndCall:
           libcutils.property_get("ro.moz.ril.extra_int_2nd_call", "false") == "true",
         haveQueryIccLockRetryCount:
           libcutils.property_get("ro.moz.ril.query_icc_count", "false") == "true",
         sendStkProfileDownload:
           libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true",
         dataRegistrationOnDemand:
-          libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true"
+          libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true",
+        subscriptionControl:
+          libcutils.property_get("ro.moz.ril.subscription_control", "false") == "true"
       },
       rilEmergencyNumbers: libcutils.property_get("ril.ecclist") ||
                            libcutils.property_get("ro.ril.ecclist")
     };
 
     try {
       options.cellBroadcastDisabled =
         Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -124,46 +124,35 @@ this.REQUEST_GET_SMSC_ADDRESS = 100;
 this.REQUEST_SET_SMSC_ADDRESS = 101;
 this.REQUEST_REPORT_SMS_MEMORY_STATUS = 102;
 this.REQUEST_REPORT_STK_SERVICE_IS_RUNNING = 103;
 this.REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE = 104;
 this.REQUEST_ISIM_AUTHENTICATION = 105;
 this.REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU = 106;
 this.REQUEST_STK_SEND_ENVELOPE_WITH_STATUS = 107;
 this.REQUEST_VOICE_RADIO_TECH = 108;
-this.REQUEST_DIAL_EMERGENCY_CALL = 10016;
 
-// Mozilla-specific request codes
-this.REQUEST_GET_UNLOCK_RETRY_COUNT = 150;
+// Flame specific parcel types.
+this.REQUEST_SET_UICC_SUBSCRIPTION = 114;
+this.REQUEST_GET_UICC_SUBSCRIPTION = 116;
 
-// Akami/Maguro specific parcel types.
-this.REQUEST_IMS_REGISTRATION_STATE = 106;
-this.REQUEST_IMS_SEND_SMS = 107;
-this.REQUEST_GET_DATA_CALL_PROFILE = 108;
-this.REQUEST_SET_UICC_SUBSCRIPTION = 109;
-this.REQUEST_SET_DATA_SUBSCRIPTION = 110;
-this.REQUEST_GET_UICC_SUBSCRIPTION = 111;
-this.REQUEST_GET_DATA_SUBSCRIPTION = 112;
-this.REQUEST_SET_SUBSCRIPTION_MODE = 113;
-this.REQUEST_SET_TRANSMIT_POWER = 114;
-this.REQUEST_SETUP_QOS = 115;
-this.REQUEST_RELEASE_QOS = 116;
-this.REQUEST_GET_QOS_STATUS = 117;
-this.REQUEST_MODIFY_QOS = 118;
-this.REQUEST_SUSPEND_QOS = 119;
-this.REQUEST_RESUME_QOS = 120;
+// UICC Secure Access.
+this.REQUEST_SIM_OPEN_CHANNEL = 121;
+this.REQUEST_SIM_CLOSE_CHANNEL = 122;
+this.REQUEST_SIM_ACCESS_CHANNEL = 123;
+
+// Mozilla specific parcel type.
+this.REQUEST_GET_UNLOCK_RETRY_COUNT = 150;
 
 // Fugu specific parcel types.
 this.RIL_REQUEST_GPRS_ATTACH = 5018;
 this.RIL_REQUEST_GPRS_DETACH = 5019;
 
-// UICC Secure Access
-this.REQUEST_SIM_OPEN_CHANNEL = 121;
-this.REQUEST_SIM_CLOSE_CHANNEL = 122;
-this.REQUEST_SIM_ACCESS_CHANNEL = 123;
+// Galaxy S2 specific parcel type.
+this.REQUEST_DIAL_EMERGENCY_CALL = 10016;
 
 this.RESPONSE_TYPE_SOLICITED = 0;
 this.RESPONSE_TYPE_UNSOLICITED = 1;
 
 this.UNSOLICITED_RESPONSE_BASE = 1000;
 this.UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED = 1000;
 this.UNSOLICITED_RESPONSE_CALL_STATE_CHANGED = 1001;
 this.UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002;
@@ -194,26 +183,17 @@ this.UNSOLICITED_CDMA_OTA_PROVISION_STAT
 this.UNSOLICITED_CDMA_INFO_REC = 1027;
 this.UNSOLICITED_OEM_HOOK_RAW = 1028;
 this.UNSOLICITED_RINGBACK_TONE = 1029;
 this.UNSOLICITED_RESEND_INCALL_MUTE = 1030;
 this.UNSOLICITED_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 1031;
 this.UNSOLICITED_CDMA_PRL_CHANGED = 1032;
 this.UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE = 1033;
 this.UNSOLICITED_RIL_CONNECTED = 1034;
-
-// Akami/Maguro specific parcels.
-this.UNSOLICITED_VOICE_RADIO_TECH_CHANGED = 1034;
-this.UNSOLICITED_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1035;
-this.UNSOLICITED_RESPONSE_TETHERED_MODE_STATE_CHANGED = 1036;
-this.UNSOLICITED_RESPONSE_DATA_NETWORK_STATE_CHANGED = 1037;
-this.UNSOLICITED_ON_SS = 1038;
-this.UNSOLICITED_STK_CC_ALPHA_NOTIFY = 1039;
-this.UNSOLICITED_UICC_SUBSCRIPTION_STATUS_CHANGED = 1040;
-this.UNSOLICITED_QOS_STATE_CHANGED_IND = 1041;
+this.UNSOLICITED_VOICE_RADIO_TECH_CHANGED = 1035;
 
 this.ERROR_SUCCESS = 0;
 this.ERROR_RADIO_NOT_AVAILABLE = 1;
 this.ERROR_GENERIC_FAILURE = 2;
 this.ERROR_PASSWORD_INCORRECT = 3;
 this.ERROR_SIM_PIN2 = 4;
 this.ERROR_SIM_PUK2 = 5;
 this.ERROR_REQUEST_NOT_SUPPORTED = 6;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -91,16 +91,19 @@ let RILQUIRKS_EXTRA_UINT32_2ND_CALL;
 let RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT;
 
 // Ril quirk to Send STK Profile Download
 let RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD;
 
 // Ril quirk to attach data registration on demand.
 let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND;
 
+// Ril quirk to control the uicc subscription.
+let RILQUIRKS_SUBSCRIPTION_CONTROL;
+
 function BufObject(aContext) {
   this.context = aContext;
 }
 BufObject.prototype = {
   context: null,
 
   mToken: 0,
   mTokenRequestMap: null,
@@ -1290,17 +1293,17 @@ RilObject.prototype = {
     }
 
     let Buf = this.context.Buf;
     Buf.newParcel(REQUEST_SIM_OPEN_CHANNEL, options);
     Buf.writeString(options.aid);
     Buf.sendParcel();
   },
 
-/**
+  /**
    * Exchange APDU data on an open Logical UICC channel
    */
   iccExchangeAPDU: function(options) {
     if (DEBUG) this.context.debug("iccExchangeAPDU: " + JSON.stringify(options));
 
     let cla = options.apdu.cla;
     let command = options.apdu.command;
     let channel = options.channel;
@@ -1336,16 +1339,33 @@ RilObject.prototype = {
     let Buf = this.context.Buf;
     Buf.newParcel(REQUEST_SIM_CLOSE_CHANNEL, options);
     Buf.writeInt32(1);
     Buf.writeInt32(options.channel);
     Buf.sendParcel();
   },
 
   /**
+   * Enable/Disable UICC subscription
+   */
+  setUiccSubscription: function(options) {
+    if (DEBUG) {
+      this.context.debug("setUiccSubscription: " + JSON.stringify(options));
+    }
+
+    let Buf = this.context.Buf;
+    Buf.newParcel(REQUEST_SET_UICC_SUBSCRIPTION, options);
+    Buf.writeInt32(this.context.clientId);
+    Buf.writeInt32(options.appIndex);
+    Buf.writeInt32(this.context.clientId);
+    Buf.writeInt32(options.enabled ? 1 : 0);
+    Buf.sendParcel();
+  },
+
+  /**
    * Tell the radio to choose a specific voice/data network
    */
   selectNetwork: function(options) {
     if (DEBUG) {
       this.context.debug("Setting manual network selection: " +
                          options.mcc + ", " + options.mnc);
     }
 
@@ -3190,20 +3210,28 @@ RilObject.prototype = {
     if (this._waitingRadioTech) {
       return;
     }
 
     this.iccStatus = iccStatus;
     let newCardState;
     let index = this._isCdma ? iccStatus.cdmaSubscriptionAppIndex :
                                iccStatus.gsmUmtsSubscriptionAppIndex;
-    let app = iccStatus.apps[index];
+
+    if (RILQUIRKS_SUBSCRIPTION_CONTROL && index === -1) {
+      // Should enable uicc scription.
+      for (let i = 0; i < iccStatus.apps.length; i++) {
+        this.setUiccSubscription({appIndex: i, enabled: true});
+      }
+      return;
+    }
 
     // When |iccStatus.cardState| is not CARD_STATE_PRESENT or have incorrect
     // app information, we can not get iccId. So treat ICC as undetected.
+    let app = iccStatus.apps[index];
     if (iccStatus.cardState !== CARD_STATE_PRESENT || !app) {
       if (this.cardState !== GECKO_CARDSTATE_UNDETECTED) {
         this.operator = null;
         // We should send |cardstatechange| before |iccinfochange|, otherwise we
         // may lost cardstatechange event when icc card becomes undetected.
         this.cardState = GECKO_CARDSTATE_UNDETECTED;
         this.sendChromeMessage({rilMessageType: "cardstatechange",
                                 cardState: this.cardState});
@@ -6338,16 +6366,18 @@ RilObject.prototype[REQUEST_GET_SMSC_ADD
 
   options.smscAddress = this.SMSC;
   options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
   this.sendChromeMessage(options);
 };
 RilObject.prototype[REQUEST_SET_SMSC_ADDRESS] = null;
 RilObject.prototype[REQUEST_REPORT_SMS_MEMORY_STATUS] = null;
 RilObject.prototype[REQUEST_REPORT_STK_SERVICE_IS_RUNNING] = null;
+RilObject.prototype[REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE] = null;
+RilObject.prototype[REQUEST_ISIM_AUTHENTICATION] = null;
 RilObject.prototype[REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU] = null;
 RilObject.prototype[REQUEST_STK_SEND_ENVELOPE_WITH_STATUS] = function REQUEST_STK_SEND_ENVELOPE_WITH_STATUS(length, options) {
   if (options.rilRequestError) {
     this.acknowledgeGsmSms(false, PDU_FCS_UNSPECIFIED);
     return;
   }
 
   let Buf = this.context.Buf;
@@ -6377,16 +6407,18 @@ RilObject.prototype[REQUEST_VOICE_RADIO_
       this.context.debug("Error when getting voice radio tech: " +
                          options.rilRequestError);
     }
     return;
   }
   let radioTech = this.context.Buf.readInt32List();
   this._processRadioTech(radioTech[0]);
 };
+RilObject.prototype[REQUEST_SET_UICC_SUBSCRIPTION] = null;
+RilObject.prototype[REQUEST_GET_UICC_SUBSCRIPTION] = null;
 RilObject.prototype[REQUEST_GET_UNLOCK_RETRY_COUNT] = function REQUEST_GET_UNLOCK_RETRY_COUNT(length, options) {
   options.success = (options.rilRequestError === 0);
   if (!options.success) {
     options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
   }
   options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1;
   this.sendChromeMessage(options);
 };
@@ -6525,16 +6557,17 @@ RilObject.prototype[UNSOLICITED_ON_USSD]
   }
 
   this._ussdSession = (typeCode != "0" && typeCode != "2");
 
   this.sendChromeMessage({rilMessageType: "USSDReceived",
                           message: message,
                           sessionEnded: !this._ussdSession});
 };
+RilObject.prototype[UNSOLICITED_ON_USSD_REQUEST] = null;
 RilObject.prototype[UNSOLICITED_NITZ_TIME_RECEIVED] = function UNSOLICITED_NITZ_TIME_RECEIVED() {
   let dateString = this.context.Buf.readString();
 
   // The data contained in the NITZ message is
   // in the form "yy/mm/dd,hh:mm:ss(+/-)tz,dt"
   // for example: 12/02/16,03:36:08-20,00,310410
   // See also bug 714352 - Listen for NITZ updates from rild.
 
@@ -6720,16 +6753,17 @@ RilObject.prototype[UNSOLICITED_RIL_CONN
   }
 
   this.initRILState();
   // Always ensure that we are not in emergency callback mode when init.
   this.exitEmergencyCbMode();
   // Reset radio in the case that b2g restart (or crash).
   this.setRadioEnabled({enabled: false});
 };
+RilObject.prototype[UNSOLICITED_VOICE_RADIO_TECH_CHANGED] = null;
 
 /**
  * This object exposes the functionality to parse and serialize PDU strings
  *
  * A PDU is a string containing a series of hexadecimally encoded octets
  * or nibble-swapped binary-coded decimals (BCDs). It contains not only the
  * message text but information about the sender, the SMS service center,
  * timestamp, etc.
@@ -14710,16 +14744,17 @@ let ContextPool = {
     RILQUIRKS_CALLSTATE_EXTRA_UINT32 = quirks.callstateExtraUint32;
     RILQUIRKS_V5_LEGACY = quirks.v5Legacy;
     RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = quirks.requestUseDialEmergencyCall;
     RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = quirks.simAppStateExtraFields;
     RILQUIRKS_EXTRA_UINT32_2ND_CALL = quirks.extraUint2ndCall;
     RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = quirks.haveQueryIccLockRetryCount;
     RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = quirks.sendStkProfileDownload;
     RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = quirks.dataRegistrationOnDemand;
+    RILQUIRKS_SUBSCRIPTION_CONTROL = quirks.subscriptionControl;
   },
 
   registerClient: function(aOptions) {
     let clientId = aOptions.clientId;
     this._contexts[clientId] = new Context(clientId);
   },
 };
 
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -1,16 +1,18 @@
 [DEFAULT]
 skip-if = e10s # Bug ?????? - most of these tests fail for currently unknown reasons.
 support-files =
   browser_frame_elements.html
   browser_geolocation_privatebrowsing_page.html
   network_geolocation.sjs
   page_privatestorageevent.html
   test-console-api.html
+  test_bug1004814.html
+  worker_bug1004814.js
 
 [browser_test__content.js]
 [browser_ConsoleAPITests.js]
 [browser_ConsoleStorageAPITests.js]
 [browser_ConsoleStoragePBTest_perwindowpb.js]
 [browser_autofocus_background.js]
 [browser_autofocus_preference.js]
 [browser_bug396843.js]
@@ -25,8 +27,9 @@ skip-if = buildapp != "b2g"
 support-files =
   test-webapp.webapp
   test-webapp-reinstall.webapp
   test-webapp-original.webapp
   test-webapps-permissions.html
 [browser_webapps_perms_reinstall.js]
 disabled = re-enable when bug 794920 is fixed
 [browser_xhr_sandbox.js]
+[browser_bug1004814.js]
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/browser_bug1004814.js
@@ -0,0 +1,46 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const TEST_URI = "http://example.com/browser/dom/tests/browser/test_bug1004814.html";
+
+function test() {
+  waitForExplicitFinish();
+
+  ConsoleObserver.init();
+
+  var tab = gBrowser.addTab(TEST_URI);
+  gBrowser.selectedTab = tab;
+
+  registerCleanupFunction(function () {
+    gBrowser.removeTab(tab);
+  });
+}
+
+var ConsoleObserver = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+
+  init: function() {
+    Services.obs.addObserver(this, "console-api-log-event", false);
+  },
+
+  destroy: function() {
+    Services.obs.removeObserver(this, "console-api-log-event");
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    var obj = aSubject.wrappedJSObject;
+    if (obj.arguments.length != 1 || obj.arguments[0] != 'bug1004814' ||
+        obj.level != 'timeEnd') {
+      return;
+    }
+
+    ok("timer" in obj, "ConsoleEvent contains 'timer' property");
+    ok("duration" in obj.timer, "ConsoleEvent.timer contains 'duration' property");
+    ok(obj.timer.duration > 0, "ConsoleEvent.timer.duration > 0: " + obj.timer.duration + " ~ 200ms");
+
+    this.destroy();
+    finish();
+  }
+};
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/test_bug1004814.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Console API test bug 1004814</title>
+  </head>
+  <body>
+    <script>
+
+var w = new Worker('worker_bug1004814.js');
+w.postMessage(true);
+
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/worker_bug1004814.js
@@ -0,0 +1,6 @@
+onmessage = function(evt) {
+  console.time('bug1004814');
+  setTimeout(function() {
+    console.timeEnd('bug1004814');
+  }, 200);
+}
--- a/dom/webidl/MozWifiManager.webidl
+++ b/dom/webidl/MozWifiManager.webidl
@@ -231,16 +231,27 @@ interface MozWifiManager : EventTarget {
    *            }
    * onerror: We have failed to import certificate.
    */
   DOMRequest importCert(Blob certBlob,
                         DOMString certPassword,
                         DOMString certNickname);
 
   /**
+   * Get list of imported WIFI certificates.
+   * onsuccess: We have successfully gotten imported certificate list.
+   *            request.result is an object using nickname as key, array of usage
+   *            string as value.
+   *            request.result[USAGE] = [CA_NICKNAME1, CA_NICKNAME2, ...]
+   *            USAGE string includes: "ServerCert".
+   * onerror: We have failed to list certificate.
+   */
+  DOMRequest getImportedCerts();
+
+  /**
    * Returns whether or not wifi is currently enabled.
    */
   readonly attribute boolean enabled;
 
   /**
    * Returns the MAC address of the wifi adapter.
    */
   readonly attribute DOMString macAddress;
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -90,16 +90,17 @@ DOMWifiManager.prototype = {
                       "WifiManager:getKnownNetworks:Return:OK", "WifiManager:getKnownNetworks:Return:NO",
                       "WifiManager:associate:Return:OK", "WifiManager:associate:Return:NO",
                       "WifiManager:forget:Return:OK", "WifiManager:forget:Return:NO",
                       "WifiManager:wps:Return:OK", "WifiManager:wps:Return:NO",
                       "WifiManager:setPowerSavingMode:Return:OK", "WifiManager:setPowerSavingMode:Return:NO",
                       "WifiManager:setHttpProxy:Return:OK", "WifiManager:setHttpProxy:Return:NO",
                       "WifiManager:setStaticIpMode:Return:OK", "WifiManager:setStaticIpMode:Return:NO",
                       "WifiManager:importCert:Return:OK", "WifiManager:importCert:Return:NO",
+                      "WifiManager:getImportedCerts:Return:OK", "WifiManager:getImportedCerts:Return:NO",
                       "WifiManager:wifiDown", "WifiManager:wifiUp",
                       "WifiManager:onconnecting", "WifiManager:onassociate",
                       "WifiManager:onconnect", "WifiManager:ondisconnect",
                       "WifiManager:onwpstimeout", "WifiManager:onwpsfail",
                       "WifiManager:onwpsoverlap", "WifiManager:connectionInfoUpdate",
                       "WifiManager:onconnectingfailed"];
     this.initDOMRequestHelper(aWindow, messages);
     this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
@@ -170,16 +171,29 @@ DOMWifiManager.prototype = {
 
     let info = Cu.createObjectIn(this._window);
     Object.defineProperties(info, propList);
     Cu.makeObjectPropsNormal(info);
 
     return info;
   },
 
+  _convertWifiCertificateList: function(aList) {
+    let propList = {};
+    for (let k in aList) {
+      propList[k] = this._genReadonlyPropDesc(aList[k]);
+    }
+
+    let list = Cu.createObjectIn(this._window);
+    Object.defineProperties(list, propList);
+    Cu.makeObjectPropsNormal(list);
+
+    return list;
+  },
+
   _sendMessageForRequest: function(name, data, request) {
     let id = this.getRequestId(request);
     this._mm.sendAsyncMessage(name, { data: data, rid: id, mid: this._id });
   },
 
   receiveMessage: function(aMessage) {
     let msg = aMessage.json;
     if (msg.mid && msg.mid != this._id)
@@ -261,16 +275,24 @@ DOMWifiManager.prototype = {
       case "WifiManager:importCert:Return:OK":
         Services.DOMRequest.fireSuccess(request, this._convertWifiCertificateInfo(msg.data));
         break;
 
       case "WifiManager:importCert:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
+      case "WifiManager:getImportedCerts:Return:OK":
+        Services.DOMRequest.fireSuccess(request, this._convertWifiCertificateList(msg.data));
+        break;
+
+      case "WifiManager:getImportedCerts:Return:NO":
+        Services.DOMRequest.fireError(request, msg.data);
+        break;
+
       case "WifiManager:wifiDown":
         this._enabled = false;
         this._currentNetwork = null;
         this._fireEnabledOrDisabled(false);
         break;
 
       case "WifiManager:wifiUp":
         this._enabled = true;
@@ -419,16 +441,22 @@ DOMWifiManager.prototype = {
                                 {
                                   certBlob: certBlob,
                                   certPassword: certPassword,
                                   certNickname: certNickname
                                 }, request);
     return request;
   },
 
+  getImportedCerts: function nsIDOMWifiManager_getImportedCerts() {
+    var request = this.createRequest();
+    this._sendMessageForRequest("WifiManager:getImportedCerts", null, request);
+    return request;
+  },
+
   get enabled() {
     return this._enabled;
   },
 
   get macAddress() {
     return this._macAddress;
   },
 
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1641,16 +1641,17 @@ function WifiWorker() {
                .getService(Ci.nsIMessageListenerManager);
   const messages = ["WifiManager:getNetworks", "WifiManager:getKnownNetworks",
                     "WifiManager:associate", "WifiManager:forget",
                     "WifiManager:wps", "WifiManager:getState",
                     "WifiManager:setPowerSavingMode",
                     "WifiManager:setHttpProxy",
                     "WifiManager:setStaticIpMode",
                     "WifiManager:importCert",
+                    "WifiManager:getImportedCerts",
                     "child-process-shutdown"];
 
   messages.forEach((function(msgName) {
     this._mm.addMessageListener(msgName, this);
   }).bind(this));
 
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
 
@@ -2596,16 +2597,19 @@ WifiWorker.prototype = {
         this.setHttpProxy(msg);
         break;
       case "WifiManager:setStaticIpMode":
         this.setStaticIpMode(msg);
         break;
       case "WifiManager:importCert":
         this.importCert(msg);
         break;
+      case "WifiManager:getImportedCerts":
+        this.getImportedCerts(msg);
+        break;
       case "WifiManager:getState": {
         let i;
         if ((i = this._domManagers.indexOf(msg.manager)) === -1) {
           this._domManagers.push(msg.manager);
         }
 
         let net = this.currentNetwork ? netToDOM(this.currentNetwork) : null;
         return { network: net,
@@ -3110,16 +3114,54 @@ WifiWorker.prototype = {
           usage: usageArray
         }, msg);
       } else {
         self._sendMessage(message, false, "Import Cert failed", msg);
       }
     });
   },
 
+  getImportedCerts: function getImportedCerts(msg) {
+    const message = "WifiManager:getImportedCerts:Return";
+    let self = this;
+
+    let certDB2 = Cc["@mozilla.org/security/x509certdb;1"]
+                  .getService(Ci.nsIX509CertDB2);
+    if (!certDB2) {
+      self._sendMessage(message, false, "Failed to query NSS DB service", msg);
+    }
+
+    let certList = certDB2.getCerts();
+    if (!certList) {
+      self._sendMessage(message, false, "Failed to get certificate List", msg);
+    }
+
+    let certListEnum = certList.getEnumerator();
+    if (!certListEnum) {
+      self._sendMessage(message, false, "Failed to get certificate List enumerator", msg);
+    }
+    let importedCerts = {
+      ServerCert: [],
+    };
+    let UsageMapping = {
+      SERVERCERT: "ServerCert",
+    };
+
+    while (certListEnum.hasMoreElements()) {
+      let certInfo = certListEnum.getNext().QueryInterface(Ci.nsIX509Cert3);
+      let certNicknameInfo = /WIFI\_([A-Z]*)\_(.*)/.exec(certInfo.nickname);
+      if (!certNicknameInfo) {
+        continue;
+      }
+      importedCerts[UsageMapping[certNicknameInfo[1]]].push(certNicknameInfo[2]);
+    }
+
+    self._sendMessage(message, true, importedCerts, msg);
+  },
+
   // 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.
   get worker() { throw "Not implemented"; },
 
   shutdown: function() {
     debug("shutting down ...");
     this.queueRequest({command: "setWifiEnabled", value: false}, function(data) {
       this.setWifiEnabled(false, this._setWifiEnabledCallback.bind(this));
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2106,17 +2106,18 @@ WorkerPrivateParent<Derived>::WorkerPriv
                                            LoadInfo& aLoadInfo)
 : mMutex("WorkerPrivateParent Mutex"),
   mCondVar(mMutex, "WorkerPrivateParent CondVar"),
   mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
   mParent(aParent), mScriptURL(aScriptURL),
   mSharedWorkerName(aSharedWorkerName), mBusyCount(0), mMessagePortSerial(0),
   mParentStatus(Pending), mParentSuspended(false),
   mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
-  mWorkerType(aWorkerType)
+  mWorkerType(aWorkerType),
+  mCreationTimeStamp(TimeStamp::Now())
 {
   SetIsDOMBinding();
 
   MOZ_ASSERT_IF(IsSharedWorker(), !aSharedWorkerName.IsVoid() &&
                                   NS_IsMainThread());
   MOZ_ASSERT_IF(!IsSharedWorker(), aSharedWorkerName.IsEmpty());
 
   if (aLoadInfo.mWindow) {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -236,16 +236,17 @@ private:
 
   uint64_t mBusyCount;
   uint64_t mMessagePortSerial;
   Status mParentStatus;
   bool mParentSuspended;
   bool mIsChromeWorker;
   bool mMainThreadObjectsForgotten;
   WorkerType mWorkerType;
+  TimeStamp mCreationTimeStamp;
 
 protected:
   // The worker is owned by its thread, which is represented here.  This is set
   // in Construct() and emptied by WorkerFinishedRunnable, and conditionally
   // traversed by the cycle collector if the busy count is zero.
   nsRefPtr<WorkerPrivate> mSelfRef;
 
   WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent,
@@ -503,16 +504,21 @@ public:
 
   nsIURI*
   GetResolvedScriptURI() const
   {
     AssertIsOnMainThread();
     return mLoadInfo.mResolvedScriptURI;
   }
 
+  TimeStamp CreationTimeStamp() const
+  {
+    return mCreationTimeStamp;
+  }
+
   nsIPrincipal*
   GetPrincipal() const
   {
     AssertIsOnMainThread();
     return mLoadInfo.mPrincipal;
   }
 
   // This method allows the principal to be retrieved off the main thread.
--- a/editor/libeditor/base/CreateElementTxn.cpp
+++ b/editor/libeditor/base/CreateElementTxn.cpp
@@ -19,16 +19,17 @@
 #include "nsMemory.h"
 #include "nsReadableUtils.h"
 #include "nsStringFwd.h"
 #include "nsString.h"
 #include "nsAString.h"
 #include <algorithm>
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 CreateElementTxn::CreateElementTxn()
   : EditTxn()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTxn, EditTxn,
                                    mParent,
@@ -55,54 +56,50 @@ NS_IMETHODIMP CreateElementTxn::Init(nsE
 }
 
 
 NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
 {
   NS_ASSERTION(mEditor && mParent, "bad state");
   NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
 
-  nsCOMPtr<dom::Element> newContent;
-
-  //new call to use instead to get proper HTML element, bug# 39919
-  nsresult result = mEditor->CreateHTMLContent(mTag, getter_AddRefs(newContent));
-  NS_ENSURE_SUCCESS(result, result);
+  ErrorResult rv;
+  nsCOMPtr<Element> newContent = mEditor->CreateHTMLContent(mTag, rv);
+  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
   NS_ENSURE_STATE(newContent);
 
   mNewNode = newContent;
   // Try to insert formatting whitespace for the new node:
   mEditor->MarkNodeDirty(mNewNode);
 
   // insert the new node
   if (CreateElementTxn::eAppend == int32_t(mOffsetInParent)) {
-    ErrorResult rv;
     mParent->AppendChild(*mNewNode, rv);
     return rv.ErrorCode();
   }
 
 
   mOffsetInParent = std::min(mOffsetInParent, mParent->GetChildCount());
 
   // note, it's ok for mRefNode to be null.  that means append
   mRefNode = mParent->GetChildAt(mOffsetInParent);
 
-  ErrorResult rv;
   mParent->InsertBefore(*mNewNode, mRefNode, rv);
   NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
 
   // only set selection to insertion point if editor gives permission
   bool bAdjustSelection;
   mEditor->ShouldTxnSetSelection(&bAdjustSelection);
   if (!bAdjustSelection) {
     // do nothing - dom range gravity will adjust selection
     return NS_OK;
   }
 
   nsCOMPtr<nsISelection> selection;
-  result = mEditor->GetSelection(getter_AddRefs(selection));
+  nsresult result = mEditor->GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(result, result);
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIContent> parentContent = do_QueryInterface(mParent);
   NS_ENSURE_STATE(parentContent);
 
   result = selection->CollapseNative(parentContent,
                                      parentContent->IndexOf(newContent) + 1);
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -26,16 +26,17 @@
 #include "mozInlineSpellChecker.h"      // for mozInlineSpellChecker
 #include "mozilla/IMEStateManager.h"    // for IMEStateManager
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/dom/Selection.h"      // for Selection, etc
 #include "mozilla/Services.h"           // for GetObserverService
 #include "mozilla/TextComposition.h"    // for TextComposition
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"        // for Element, nsINode::AsElement
+#include "mozilla/dom/Text.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsAString.h"                  // for nsAString_internal::Length, etc
 #include "nsCCUncollectableMarker.h"    // for nsCCUncollectableMarker
 #include "nsCaret.h"                    // for nsCaret
 #include "nsCaseTreatment.h"
 #include "nsCharTraits.h"               // for NS_IS_HIGH_SURROGATE, etc
 #include "nsComponentManagerUtils.h"    // for do_CreateInstance
 #include "nsComputedDOMStyle.h"         // for nsComputedDOMStyle
@@ -1374,16 +1375,23 @@ NS_IMETHODIMP nsEditor::CreateNode(const
 
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->DidCreateNode(aTag, *aNewNode, aParent, aPosition, result);
 
   return result;
 }
 
 
+nsresult
+nsEditor::InsertNode(nsIContent* aContent, nsINode* aParent, int32_t aPosition)
+{
+  MOZ_ASSERT(aContent && aParent);
+  return InsertNode(GetAsDOMNode(aContent), GetAsDOMNode(aParent), aPosition);
+}
+
 NS_IMETHODIMP nsEditor::InsertNode(nsIDOMNode * aNode,
                                    nsIDOMNode * aParent,
                                    int32_t      aPosition)
 {
   int32_t i;
   nsAutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
 
   for (i = 0; i < mActionListeners.Count(); i++)
@@ -1566,25 +1574,26 @@ nsEditor::ReplaceContainer(nsINode* aNod
   *outNode = nullptr;
 
   nsCOMPtr<nsIContent> parent = aNode->GetParent();
   NS_ENSURE_STATE(parent);
 
   int32_t offset = parent->IndexOf(aNode);
 
   // create new container
-  //new call to use instead to get proper HTML element, bug# 39919
-  nsresult res = CreateHTMLContent(aNodeType, outNode);
-  NS_ENSURE_SUCCESS(res, res);
+  ErrorResult rv;
+  *outNode = CreateHTMLContent(aNodeType, rv).take();
+  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
 
   nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(*outNode);
   
   nsIDOMNode* inNode = aNode->AsDOMNode();
 
   // set attribute if needed
+  nsresult res;
   if (aAttribute && aValue && !aAttribute->IsEmpty()) {
     res = elem->SetAttribute(*aAttribute, *aValue);
     NS_ENSURE_SUCCESS(res, res);
   }
   if (aCloneAttributes) {
     res = CloneAttributes(elem, inNode);
     NS_ENSURE_SUCCESS(res, res);
   }
@@ -1689,23 +1698,22 @@ nsEditor::InsertContainerAbove(nsIConten
 {
   MOZ_ASSERT(aNode);
 
   nsCOMPtr<nsIContent> parent = aNode->GetParent();
   NS_ENSURE_STATE(parent);
   int32_t offset = parent->IndexOf(aNode);
 
   // create new container
-  nsCOMPtr<dom::Element> newContent;
-
-  //new call to use instead to get proper HTML element, bug# 39919
-  nsresult res = CreateHTMLContent(aNodeType, getter_AddRefs(newContent));
-  NS_ENSURE_SUCCESS(res, res);
+  ErrorResult rv;
+  nsCOMPtr<Element> newContent = CreateHTMLContent(aNodeType, rv);
+  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
 
   // set attribute if needed
+  nsresult res;
   if (aAttribute && aValue && !aAttribute->IsEmpty()) {
     nsIDOMNode* elem = newContent->AsDOMNode();
     res = static_cast<nsIDOMElement*>(elem)->SetAttribute(*aAttribute, *aValue);
     NS_ENSURE_SUCCESS(res, res);
   }
   
   // notify our internal selection state listener
   nsAutoInsertContainerSelNotify selNotify(mRangeUpdater);
@@ -2430,16 +2438,26 @@ nsEditor::InsertTextImpl(const nsAString
   }
 
   *aInOutNode = node->AsDOMNode();
   *aInOutOffset = static_cast<int32_t>(offset);
   return NS_OK;
 }
 
 
+nsresult nsEditor::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
+                                              Text* aTextNode,
+                                              int32_t aOffset,
+                                              bool aSuppressIME)
+{
+  return InsertTextIntoTextNodeImpl(aStringToInsert,
+      static_cast<nsIDOMCharacterData*>(GetAsDOMNode(aTextNode)),
+      aOffset, aSuppressIME);
+}
+
 nsresult nsEditor::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, 
                                               nsIDOMCharacterData *aTextNode, 
                                               int32_t aOffset,
                                               bool aSuppressIME)
 {
   nsRefPtr<EditTxn> txn;
   nsresult result = NS_OK;
   bool isIMETransaction = false;
@@ -3476,18 +3494,24 @@ nsEditor::IsDescendantOfEditorRoot(nsINo
 {
   NS_ENSURE_TRUE(aNode, false);
   nsCOMPtr<nsIContent> root = GetEditorRoot();
   NS_ENSURE_TRUE(root, false);
 
   return nsContentUtils::ContentIsDescendantOf(aNode, root);
 }
 
-bool 
-nsEditor::IsContainer(nsIDOMNode *aNode)
+bool
+nsEditor::IsContainer(nsINode* aNode)
+{
+  return aNode ? true : false;
+}
+
+bool
+nsEditor::IsContainer(nsIDOMNode* aNode)
 {
   return aNode ? true : false;
 }
 
 static inline bool
 IsElementVisible(dom::Element* aElement)
 {
   if (aElement->GetPrimaryFrame()) {
@@ -3548,21 +3572,24 @@ IsElementVisible(dom::Element* aElement)
 bool 
 nsEditor::IsEditable(nsIDOMNode *aNode)
 {
   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
   return IsEditable(content);
 }
 
 bool
-nsEditor::IsEditable(nsIContent *aNode)
+nsEditor::IsEditable(nsINode* aNode)
 {
   NS_ENSURE_TRUE(aNode, false);
 
-  if (IsMozEditorBogusNode(aNode) || !IsModifiableNode(aNode)) return false;
+  if (!aNode->IsNodeOfType(nsINode::eCONTENT) || IsMozEditorBogusNode(aNode) ||
+      !IsModifiableNode(aNode)) {
+    return false;
+  }
 
   // see if it has a frame.  If so, we'll edit it.
   // special case for textnodes: frame must have width.
   if (aNode->IsElement() && !IsElementVisible(aNode->AsElement())) {
     // If the element has no frame, it's not editable.  Note that we
     // need to check IsElement() here, because some of our tests
     // rely on frameless textnodes being visible.
     return false;
@@ -3572,21 +3599,22 @@ nsEditor::IsEditable(nsIContent *aNode)
     case nsIDOMNode::TEXT_NODE:
       return true; // element or text node; not invisible
     default:
       return false;
   }
 }
 
 bool
-nsEditor::IsMozEditorBogusNode(nsIContent *element)
-{
-  return element &&
-         element->AttrValueIs(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
-                              kMOZEditorBogusNodeValue, eCaseMatters);
+nsEditor::IsMozEditorBogusNode(nsINode* element)
+{
+  return element && element->IsElement() &&
+         element->AsElement()->AttrValueIs(kNameSpaceID_None,
+             kMOZEditorBogusNodeAttrAtom, kMOZEditorBogusNodeValue,
+             eCaseMatters);
 }
 
 uint32_t
 nsEditor::CountEditableChildren(nsINode* aNode)
 {
   MOZ_ASSERT(aNode);
   uint32_t count = 0;
   for (nsIContent* child = aNode->GetFirstChild();
@@ -4731,32 +4759,41 @@ nsresult nsEditor::ClearSelection()
 {
   nsCOMPtr<nsISelection> selection;
   nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(res, res);
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
   return selection->RemoveAllRanges();  
 }
 
-nsresult
-nsEditor::CreateHTMLContent(const nsAString& aTag, dom::Element** aContent)
+already_AddRefed<Element>
+nsEditor::CreateHTMLContent(const nsAString& aTag, ErrorResult& rv)
 {
   nsCOMPtr<nsIDocument> doc = GetDocument();
-  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+  if (!doc) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
   // XXX Wallpaper over editor bug (editor tries to create elements with an
   //     empty nodename).
   if (aTag.IsEmpty()) {
     NS_ERROR("Don't pass an empty tag to nsEditor::CreateHTMLContent, "
              "check caller.");
-    return NS_ERROR_FAILURE;
-  }
-
-  return doc->CreateElem(aTag, nullptr, kNameSpaceID_XHTML,
-                         reinterpret_cast<nsIContent**>(aContent));
+    rv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIContent> ret;
+  nsresult res = doc->CreateElem(aTag, nullptr, kNameSpaceID_XHTML,
+                                 getter_AddRefs(ret));
+  if (NS_FAILED(res)) {
+    rv.Throw(res);
+  }
+  return dont_AddRef(ret.forget().take()->AsElement());
 }
 
 nsresult
 nsEditor::SetAttributeOrEquivalent(nsIDOMElement * aElement,
                                    const nsAString & aAttribute,
                                    const nsAString & aValue,
                                    bool aSuppressTransaction)
 {
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -62,23 +62,25 @@ class nsISelection;
 class nsISupports;
 class nsITransaction;
 class nsIWidget;
 class nsRange;
 class nsString;
 class nsTransactionManager;
 
 namespace mozilla {
+class ErrorResult;
 class TextComposition;
 
 namespace dom {
 class DataTransfer;
 class Element;
 class EventTarget;
 class Selection;
+class Text;
 }  // namespace dom
 }  // namespace mozilla
 
 namespace mozilla {
 namespace widget {
 struct IMEState;
 } // namespace widget
 } // namespace mozilla
@@ -190,27 +192,33 @@ public:
 
   nsresult MarkNodeDirty(nsINode* aNode);
   virtual bool IsModifiableNode(nsINode *aNode);
 
   NS_IMETHOD InsertTextImpl(const nsAString& aStringToInsert, 
                                nsCOMPtr<nsIDOMNode> *aInOutNode, 
                                int32_t *aInOutOffset,
                                nsIDOMDocument *aDoc);
+  nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
+                                      mozilla::dom::Text* aTextNode,
+                                      int32_t aOffset,
+                                      bool aSuppressIME = false);
   nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, 
                                       nsIDOMCharacterData *aTextNode, 
                                       int32_t aOffset,
                                       bool aSuppressIME = false);
   NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
                                  EStripWrappers aStripWrappers);
   NS_IMETHOD DeleteSelectionAndCreateNode(const nsAString& aTag,
                                            nsIDOMNode ** aNewNode);
 
   /* helper routines for node/parent manipulations */
   nsresult DeleteNode(nsINode* aNode);
+  nsresult InsertNode(nsIContent* aContent, nsINode* aParent,
+                      int32_t aPosition);
   nsresult ReplaceContainer(nsINode* inNode,
                             mozilla::dom::Element** outNode,
                             const nsAString& aNodeType,
                             const nsAString* aAttribute = nullptr,
                             const nsAString* aValue = nullptr,
                             bool aCloneAttributes = false);
   nsresult ReplaceContainer(nsIDOMNode *inNode, 
                             nsCOMPtr<nsIDOMNode> *outNode, 
@@ -233,20 +241,19 @@ public:
                                 const nsAString *aValue = nullptr);
   nsresult JoinNodes(nsINode* aNodeToKeep, nsIContent* aNodeToMove);
   nsresult MoveNode(nsINode* aNode, nsINode* aParent, int32_t aOffset);
   nsresult MoveNode(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aOffset);
 
   /* Method to replace certain CreateElementNS() calls. 
      Arguments:
       nsString& aTag          - tag you want
-      nsIContent** aContent   - returned Content that was created with above namespace.
   */
-  nsresult CreateHTMLContent(const nsAString& aTag,
-                             mozilla::dom::Element** aContent);
+  already_AddRefed<mozilla::dom::Element>
+    CreateHTMLContent(const nsAString& aTag, mozilla::ErrorResult& rv);
 
   // IME event handlers
   virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent);
   virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0;
   void EndIMEComposition();
 
   void SwitchTextDirectionTo(uint32_t aDirection);
 
@@ -580,24 +587,25 @@ public:
 
   /** returns true if aNode is a descendant of our root node */
   bool IsDescendantOfRoot(nsIDOMNode* inNode);
   bool IsDescendantOfRoot(nsINode* inNode);
   bool IsDescendantOfEditorRoot(nsIDOMNode* aNode);
   bool IsDescendantOfEditorRoot(nsINode* aNode);
 
   /** returns true if aNode is a container */
-  virtual bool IsContainer(nsIDOMNode *aNode);
+  virtual bool IsContainer(nsINode* aNode);
+  virtual bool IsContainer(nsIDOMNode* aNode);
 
   /** returns true if aNode is an editable node */
   bool IsEditable(nsIDOMNode *aNode);
-  virtual bool IsEditable(nsIContent *aNode);
+  virtual bool IsEditable(nsINode* aNode);
 
   /** returns true if aNode is a MozEditorBogus node */
-  bool IsMozEditorBogusNode(nsIContent *aNode);
+  bool IsMozEditorBogusNode(nsINode* aNode);
 
   /** counts number of editable child nodes */
   uint32_t CountEditableChildren(nsINode* aNode);
   
   /** Find the deep first and last children. */
   nsINode* GetFirstEditableNode(nsINode* aRoot);
 
   /**
--- a/editor/libeditor/base/nsEditorUtils.cpp
+++ b/editor/libeditor/base/nsEditorUtils.cpp
@@ -133,49 +133,46 @@ nsDOMSubtreeIterator::Init(nsIDOMRange* 
   NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE);
   return mIter->Init(aRange);
 }
 
 /******************************************************************************
  * some general purpose editor utils
  *****************************************************************************/
 
-bool 
-nsEditorUtils::IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t *aOffset) 
+bool
+nsEditorUtils::IsDescendantOf(nsINode* aNode, nsINode* aParent, int32_t* aOffset)
 {
-  NS_ENSURE_TRUE(aNode || aParent, false);
-  if (aNode == aParent) return false;
-  
-  nsCOMPtr<nsIDOMNode> parent, node = do_QueryInterface(aNode);
-  nsresult res;
-  
-  do
-  {
-    res = node->GetParentNode(getter_AddRefs(parent));
-    NS_ENSURE_SUCCESS(res, false);
-    if (parent == aParent) 
-    {
-      if (aOffset)
-      {
-        nsCOMPtr<nsIContent> pCon(do_QueryInterface(parent));
-        nsCOMPtr<nsIContent> cCon(do_QueryInterface(node));
-        if (pCon)
-        {
-          *aOffset = pCon->IndexOf(cCon);
-        }
+  MOZ_ASSERT(aNode && aParent);
+  if (aNode == aParent) {
+    return false;
+  }
+
+  for (nsCOMPtr<nsINode> node = aNode; node; node = node->GetParentNode()) {
+    if (node->GetParentNode() == aParent) {
+      if (aOffset) {
+        *aOffset = aParent->IndexOf(node);
       }
       return true;
     }
-    node = parent;
-  } while (parent);
-  
+  }
+
   return false;
 }
 
 bool
+nsEditorUtils::IsDescendantOf(nsIDOMNode* aNode, nsIDOMNode* aParent, int32_t* aOffset)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
+  NS_ENSURE_TRUE(node && parent, false);
+  return IsDescendantOf(node, parent, aOffset);
+}
+
+bool
 nsEditorUtils::IsLeafNode(nsIDOMNode *aNode)
 {
   bool hasChildren = false;
   if (aNode)
     aNode->HasChildNodes(&hasChildren);
   return !hasChildren;
 }
 
--- a/editor/libeditor/base/nsEditorUtils.h
+++ b/editor/libeditor/base/nsEditorUtils.h
@@ -199,36 +199,45 @@ class nsTrivialFunctor : public nsBoolDo
 };
 
 
 /******************************************************************************
  * general dom point utility struct
  *****************************************************************************/
 struct MOZ_STACK_CLASS DOMPoint
 {
-  nsCOMPtr<nsIDOMNode> node;
+  nsCOMPtr<nsINode> node;
   int32_t offset;
   
-  DOMPoint() : node(0),offset(0) {}
-  DOMPoint(nsIDOMNode *aNode, int32_t aOffset) : 
-                 node(aNode),offset(aOffset) {}
-  void SetPoint(nsIDOMNode *aNode, int32_t aOffset)
+  DOMPoint(nsINode* aNode, int32_t aOffset)
+    : node(aNode)
+    , offset(aOffset)
+  {}
+  DOMPoint(nsIDOMNode* aNode, int32_t aOffset)
+    : node(do_QueryInterface(aNode))
+    , offset(aOffset)
+  {}
+
+  void SetPoint(nsINode* aNode, int32_t aOffset)
   {
-    node = aNode; offset = aOffset;
+    node = aNode;
+    offset = aOffset;
   }
-  void GetPoint(nsCOMPtr<nsIDOMNode> &aNode, int32_t &aOffset)
+  void SetPoint(nsIDOMNode* aNode, int32_t aOffset)
   {
-    aNode = node; aOffset = offset;
+    node = do_QueryInterface(aNode);
+    offset = aOffset;
   }
 };
 
 
 class nsEditorUtils
 {
   public:
+    static bool IsDescendantOf(nsINode* aNode, nsINode* aParent, int32_t* aOffset = 0);
     static bool IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t *aOffset = 0);
     static bool IsLeafNode(nsIDOMNode *aNode);
 };
 
 
 class nsIDOMEvent;
 class nsISimpleEnumerator;
 class nsITransferable;
--- a/editor/libeditor/base/nsSelectionState.cpp
+++ b/editor/libeditor/base/nsSelectionState.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/dom/Selection.h"      // for Selection
 #include "nsAString.h"                  // for nsAString_internal::Length
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsEditor.h"                   // for nsEditor
 #include "nsEditorUtils.h"              // for nsEditorUtils
 #include "nsError.h"                    // for NS_OK, etc
+#include "nsIContent.h"                 // for nsIContent
 #include "nsIDOMCharacterData.h"        // for nsIDOMCharacterData
 #include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nsIDOMRange.h"                // for nsIDOMRange, etc
 #include "nsISelection.h"               // for nsISelection
 #include "nsISupportsImpl.h"            // for nsRange::Release
 #include "nsRange.h"                    // for nsRange
 #include "nsSelectionState.h"
 
@@ -84,52 +85,49 @@ nsSelectionState::RestoreSelection(nsISe
   uint32_t i, arrayCount = mArray.Length();
 
   // clear out selection
   aSel->RemoveAllRanges();
   
   // set the selection ranges anew
   for (i=0; i<arrayCount; i++)
   {
-    nsRefPtr<nsRange> range;
-    mArray[i]->GetRange(getter_AddRefs(range));
+    nsRefPtr<nsRange> range = mArray[i]->GetRange();
     NS_ENSURE_TRUE(range, NS_ERROR_UNEXPECTED);
    
     res = aSel->AddRange(range);
     if(NS_FAILED(res)) return res;
 
   }
   return NS_OK;
 }
 
 bool
 nsSelectionState::IsCollapsed()
 {
   if (1 != mArray.Length()) return false;
-  nsRefPtr<nsRange> range;
-  mArray[0]->GetRange(getter_AddRefs(range));
+  nsRefPtr<nsRange> range = mArray[0]->GetRange();
   NS_ENSURE_TRUE(range, false);
   bool bIsCollapsed = false;
   range->GetCollapsed(&bIsCollapsed);
   return bIsCollapsed;
 }
 
 bool
 nsSelectionState::IsEqual(nsSelectionState *aSelState)
 {
   NS_ENSURE_TRUE(aSelState, false);
   uint32_t i, myCount = mArray.Length(), itsCount = aSelState->mArray.Length();
   if (myCount != itsCount) return false;
   if (myCount < 1) return false;
 
   for (i=0; i<myCount; i++)
   {
-    nsRefPtr<nsRange> myRange, itsRange;
-    mArray[i]->GetRange(getter_AddRefs(myRange));
-    aSelState->mArray[i]->GetRange(getter_AddRefs(itsRange));
+    nsRefPtr<nsRange> myRange = mArray[i]->GetRange();
+    nsRefPtr<nsRange> itsRange = aSelState->mArray[i]->GetRange();
     NS_ENSURE_TRUE(myRange && itsRange, false);
   
     int16_t compResult;
     nsresult rv;
     rv = myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
     if (NS_FAILED(rv) || compResult) return false;
     rv = myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
     if (NS_FAILED(rv) || compResult) return false;
@@ -207,378 +205,432 @@ nsRangeUpdater::DropSelectionState(nsSel
   }
 
   return NS_OK;
 }
 
 // gravity methods:
 
 nsresult
-nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, int32_t aPosition)
+nsRangeUpdater::SelAdjCreateNode(nsINode* aParent, int32_t aPosition)
 {
-  if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
+  if (mLock) {
+    // lock set by Will/DidReplaceParent, etc...
+    return NS_OK;
+  }
   NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
-  uint32_t i, count = mArray.Length();
+  uint32_t count = mArray.Length();
   if (!count) {
     return NS_OK;
   }
 
-  nsRangeStore *item;
-  
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
-    
-    if ((item->startNode.get() == aParent) && (item->startOffset > aPosition))
+
+    if (item->startNode == aParent && item->startOffset > aPosition) {
       item->startOffset++;
-    if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
+    }
+    if (item->endNode == aParent && item->endOffset > aPosition) {
       item->endOffset++;
+    }
   }
   return NS_OK;
 }
 
 nsresult
+nsRangeUpdater::SelAdjCreateNode(nsIDOMNode* aParent, int32_t aPosition)
+{
+  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
+  return SelAdjCreateNode(parent, aPosition);
+}
+
+nsresult
+nsRangeUpdater::SelAdjInsertNode(nsINode* aParent, int32_t aPosition)
+{
+  return SelAdjCreateNode(aParent, aPosition);
+}
+
+nsresult
 nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, int32_t aPosition)
 {
   return SelAdjCreateNode(aParent, aPosition);
 }
 
 void
-nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode)
+nsRangeUpdater::SelAdjDeleteNode(nsINode* aNode)
 {
   if (mLock) {
     // lock set by Will/DidReplaceParent, etc...
     return;
   }
   MOZ_ASSERT(aNode);
-  uint32_t i, count = mArray.Length();
+  uint32_t count = mArray.Length();
   if (!count) {
     return;
   }
 
-  int32_t offset = 0;
-  nsCOMPtr<nsIDOMNode> parent = nsEditor::GetNodeLocation(aNode, &offset);
-  
+  nsCOMPtr<nsINode> parent = aNode->GetParentNode();
+  int32_t offset = parent ? parent->IndexOf(aNode) : -1;
+
   // check for range endpoints that are after aNode and in the same parent
-  nsRangeStore *item;
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     MOZ_ASSERT(item);
-    
-    if ((item->startNode.get() == parent) && (item->startOffset > offset))
+
+    if (item->startNode == parent && item->startOffset > offset) {
       item->startOffset--;
-    if ((item->endNode.get() == parent) && (item->endOffset > offset))
+    }
+    if (item->endNode == parent && item->endOffset > offset) {
       item->endOffset--;
-      
+    }
+
     // check for range endpoints that are in aNode
-    if (item->startNode == aNode)
-    {
+    if (item->startNode == aNode) {
       item->startNode   = parent;
       item->startOffset = offset;
     }
-    if (item->endNode == aNode)
-    {
+    if (item->endNode == aNode) {
       item->endNode   = parent;
       item->endOffset = offset;
     }
 
     // check for range endpoints that are in descendants of aNode
-    nsCOMPtr<nsIDOMNode> oldStart;
-    if (nsEditorUtils::IsDescendantOf(item->startNode, aNode))
-    {
+    nsCOMPtr<nsINode> oldStart;
+    if (nsEditorUtils::IsDescendantOf(item->startNode, aNode)) {
       oldStart = item->startNode;  // save for efficiency hack below.
       item->startNode   = parent;
       item->startOffset = offset;
     }
 
     // avoid having to call IsDescendantOf() for common case of range startnode == range endnode.
     if ((item->endNode == oldStart) || nsEditorUtils::IsDescendantOf(item->endNode, aNode))
     {
       item->endNode   = parent;
       item->endOffset = offset;
     }
   }
 }
 
+void
+nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  NS_ENSURE_TRUE(node, );
+  return SelAdjDeleteNode(node);
+}
+
 
 nsresult
-nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, int32_t aOffset, nsIDOMNode *aNewLeftNode)
+nsRangeUpdater::SelAdjSplitNode(nsINode* aOldRightNode, int32_t aOffset,
+                                nsINode* aNewLeftNode)
 {
-  if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
+  if (mLock) {
+    // lock set by Will/DidReplaceParent, etc...
+    return NS_OK;
+  }
   NS_ENSURE_TRUE(aOldRightNode && aNewLeftNode, NS_ERROR_NULL_POINTER);
-  uint32_t i, count = mArray.Length();
+  uint32_t count = mArray.Length();
   if (!count) {
     return NS_OK;
   }
 
-  int32_t offset;
-  nsCOMPtr<nsIDOMNode> parent = nsEditor::GetNodeLocation(aOldRightNode, &offset);
-  
+  nsCOMPtr<nsINode> parent = aOldRightNode->GetParentNode();
+  int32_t offset = parent ? parent->IndexOf(aOldRightNode) : -1;
+
   // first part is same as inserting aNewLeftnode
-  nsresult result = SelAdjInsertNode(parent,offset-1);
+  nsresult result = SelAdjInsertNode(parent, offset - 1);
   NS_ENSURE_SUCCESS(result, result);
 
   // next step is to check for range enpoints inside aOldRightNode
-  nsRangeStore *item;
-  
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
-    
-    if (item->startNode.get() == aOldRightNode)
-    {
-      if (item->startOffset > aOffset)
-      {
+
+    if (item->startNode == aOldRightNode) {
+      if (item->startOffset > aOffset) {
         item->startOffset -= aOffset;
-      }
-      else
-      {
+      } else {
         item->startNode = aNewLeftNode;
       }
     }
-    if (item->endNode.get() == aOldRightNode)
-    {
-      if (item->endOffset > aOffset)
-      {
+    if (item->endNode == aOldRightNode) {
+      if (item->endOffset > aOffset) {
         item->endOffset -= aOffset;
-      }
-      else
-      {
+      } else {
         item->endNode = aNewLeftNode;
       }
     }
   }
   return NS_OK;
 }
 
+nsresult
+nsRangeUpdater::SelAdjSplitNode(nsIDOMNode* aOldRightNode, int32_t aOffset,
+                                nsIDOMNode* aNewLeftNode)
+{
+  nsCOMPtr<nsINode> oldRightNode = do_QueryInterface(aOldRightNode);
+  nsCOMPtr<nsINode> newLeftNode = do_QueryInterface(aNewLeftNode);
+  return SelAdjSplitNode(oldRightNode, aOffset, newLeftNode);
+}
+
 
 nsresult
-nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode, 
-                                  nsIDOMNode *aRightNode, 
-                                  nsIDOMNode *aParent, 
-                                  int32_t aOffset,
-                                  int32_t aOldLeftNodeLength)
+nsRangeUpdater::SelAdjJoinNodes(nsINode* aLeftNode,
+                                nsINode* aRightNode,
+                                nsINode* aParent,
+                                int32_t aOffset,
+                                int32_t aOldLeftNodeLength)
 {
-  if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
+  if (mLock) {
+    // lock set by Will/DidReplaceParent, etc...
+    return NS_OK;
+  }
   NS_ENSURE_TRUE(aLeftNode && aRightNode && aParent, NS_ERROR_NULL_POINTER);
-  uint32_t i, count = mArray.Length();
+  uint32_t count = mArray.Length();
   if (!count) {
     return NS_OK;
   }
 
-  nsRangeStore *item;
-
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
-    
-    if (item->startNode.get() == aParent)
-    {
+
+    if (item->startNode == aParent) {
       // adjust start point in aParent
-      if (item->startOffset > aOffset)
-      {
+      if (item->startOffset > aOffset) {
         item->startOffset--;
-      }
-      else if (item->startOffset == aOffset)
-      {
+      } else if (item->startOffset == aOffset) {
         // join keeps right hand node
         item->startNode = aRightNode;
         item->startOffset = aOldLeftNodeLength;
       }
-    }
-    else if (item->startNode.get() == aRightNode)
-    {
+    } else if (item->startNode == aRightNode) {
       // adjust start point in aRightNode
       item->startOffset += aOldLeftNodeLength;
-    }
-    else if (item->startNode.get() == aLeftNode)
-    {
+    } else if (item->startNode == aLeftNode) {
       // adjust start point in aLeftNode
       item->startNode = aRightNode;
     }
 
-    if (item->endNode.get() == aParent)
-    {
+    if (item->endNode == aParent) {
       // adjust end point in aParent
-      if (item->endOffset > aOffset)
-      {
+      if (item->endOffset > aOffset) {
         item->endOffset--;
-      }
-      else if (item->endOffset == aOffset)
-      {
+      } else if (item->endOffset == aOffset) {
         // join keeps right hand node
         item->endNode = aRightNode;
         item->endOffset = aOldLeftNodeLength;
       }
-    }
-    else if (item->endNode.get() == aRightNode)
-    {
+    } else if (item->endNode == aRightNode) {
       // adjust end point in aRightNode
        item->endOffset += aOldLeftNodeLength;
-    }
-    else if (item->endNode.get() == aLeftNode)
-    {
+    } else if (item->endNode == aLeftNode) {
       // adjust end point in aLeftNode
       item->endNode = aRightNode;
     }
   }
-  
+
   return NS_OK;
 }
 
+nsresult
+nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode* aLeftNode,
+                                nsIDOMNode* aRightNode,
+                                nsIDOMNode* aParent,
+                                int32_t aOffset,
+                                int32_t aOldLeftNodeLength)
+{
+  nsCOMPtr<nsINode> leftNode = do_QueryInterface(aLeftNode);
+  nsCOMPtr<nsINode> rightNode = do_QueryInterface(aRightNode);
+  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
+  return SelAdjJoinNodes(leftNode, rightNode, parent, aOffset, aOldLeftNodeLength);
+}
+
 
 nsresult
-nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, const nsAString &aString)
+nsRangeUpdater::SelAdjInsertText(nsIContent* aTextNode, int32_t aOffset,
+                                 const nsAString &aString)
 {
-  if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
+  if (mLock) {
+    // lock set by Will/DidReplaceParent, etc...
+    return NS_OK;
+  }
 
   uint32_t count = mArray.Length();
   if (!count) {
     return NS_OK;
   }
-  nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aTextNode));
-  NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
-  
-  uint32_t len=aString.Length(), i;
-  nsRangeStore *item;
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  NS_ENSURE_TRUE(aTextNode, NS_ERROR_NULL_POINTER);
+
+  uint32_t len = aString.Length();
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
-    
-    if ((item->startNode.get() == node) && (item->startOffset > aOffset))
+
+    if (item->startNode == aTextNode && item->startOffset > aOffset) {
       item->startOffset += len;
-    if ((item->endNode.get() == node) && (item->endOffset > aOffset))
+    }
+    if (item->endNode == aTextNode && item->endOffset > aOffset) {
       item->endOffset += len;
+    }
   }
   return NS_OK;
 }
 
+nsresult
+nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData* aTextNode,
+                                 int32_t aOffset, const nsAString &aString)
+{
+  nsCOMPtr<nsIContent> textNode = do_QueryInterface(aTextNode);
+  return SelAdjInsertText(textNode, aOffset, aString);
+}
+
 
 nsresult
-nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength)
+nsRangeUpdater::SelAdjDeleteText(nsIContent* aTextNode, int32_t aOffset,
+                                 int32_t aLength)
 {
-  if (mLock) return NS_OK;  // lock set by Will/DidReplaceParent, etc...
+  if (mLock) {
+    // lock set by Will/DidReplaceParent, etc...
+    return NS_OK;
+  }
 
-  uint32_t i, count = mArray.Length();
+  uint32_t count = mArray.Length();
   if (!count) {
     return NS_OK;
   }
-  nsRangeStore *item;
-  nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aTextNode));
-  NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
-  
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  NS_ENSURE_TRUE(aTextNode, NS_ERROR_NULL_POINTER);
+
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
-    
-    if ((item->startNode.get() == node) && (item->startOffset > aOffset))
-    {
+
+    if (item->startNode == aTextNode && item->startOffset > aOffset) {
       item->startOffset -= aLength;
-      if (item->startOffset < 0) item->startOffset = 0;
+      if (item->startOffset < 0) {
+        item->startOffset = 0;
+      }
     }
-    if ((item->endNode.get() == node) && (item->endOffset > aOffset))
-    {
+    if (item->endNode == aTextNode && item->endOffset > aOffset) {
       item->endOffset -= aLength;
-      if (item->endOffset < 0) item->endOffset = 0;
+      if (item->endOffset < 0) {
+        item->endOffset = 0;
+      }
     }
   }
   return NS_OK;
 }
 
+nsresult
+nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData* aTextNode,
+                                 int32_t aOffset, int32_t aLength)
+{
+  nsCOMPtr<nsIContent> textNode = do_QueryInterface(aTextNode);
+  return SelAdjDeleteText(textNode, aOffset, aLength);
+}
+
 
 nsresult
 nsRangeUpdater::WillReplaceContainer()
 {
   if (mLock) return NS_ERROR_UNEXPECTED;  
   mLock = true;
   return NS_OK;
 }
 
 
 nsresult
-nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
+nsRangeUpdater::DidReplaceContainer(nsINode* aOriginalNode, nsINode* aNewNode)
 {
-  NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);  
+  NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);
   mLock = false;
 
   NS_ENSURE_TRUE(aOriginalNode && aNewNode, NS_ERROR_NULL_POINTER);
-  uint32_t i, count = mArray.Length();
+  uint32_t count = mArray.Length();
   if (!count) {
     return NS_OK;
   }
 
-  nsRangeStore *item;
-  
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
     
-    if (item->startNode.get() == aOriginalNode)
+    if (item->startNode == aOriginalNode) {
       item->startNode = aNewNode;
-    if (item->endNode.get() == aOriginalNode)
+    }
+    if (item->endNode == aOriginalNode) {
       item->endNode = aNewNode;
+    }
   }
   return NS_OK;
 }
 
+nsresult
+nsRangeUpdater::DidReplaceContainer(nsIDOMNode* aOriginalNode,
+                                    nsIDOMNode* aNewNode)
+{
+  nsCOMPtr<nsINode> originalNode = do_QueryInterface(aOriginalNode);
+  nsCOMPtr<nsINode> newNode = do_QueryInterface(aNewNode);
+  return DidReplaceContainer(originalNode, newNode);
+}
+
 
 nsresult
 nsRangeUpdater::WillRemoveContainer()
 {
   if (mLock) return NS_ERROR_UNEXPECTED;  
   mLock = true;
   return NS_OK;
 }
 
 
 nsresult
-nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aOffset, uint32_t aNodeOrigLen)
+nsRangeUpdater::DidRemoveContainer(nsINode* aNode, nsINode* aParent,
+                                   int32_t aOffset, uint32_t aNodeOrigLen)
 {
-  NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);  
+  NS_ENSURE_TRUE(mLock, NS_ERROR_UNEXPECTED);
   mLock = false;
 
   NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
-  uint32_t i, count = mArray.Length();
+  uint32_t count = mArray.Length();
   if (!count) {
     return NS_OK;
   }
 
-  nsRangeStore *item;
-  
-  for (i=0; i<count; i++)
-  {
-    item = mArray[i];
+  for (uint32_t i = 0; i < count; i++) {
+    nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE(item, NS_ERROR_NULL_POINTER);
     
-    if (item->startNode.get() == aNode)
-    {
+    if (item->startNode == aNode) {
       item->startNode = aParent;
       item->startOffset += aOffset;
+    } else if (item->startNode == aParent && item->startOffset > aOffset) {
+      item->startOffset += (int32_t)aNodeOrigLen - 1;
     }
-    else if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
-      item->startOffset += (int32_t)aNodeOrigLen-1;
       
-    if (item->endNode.get() == aNode)
-    {
+    if (item->endNode == aNode) {
       item->endNode = aParent;
       item->endOffset += aOffset;
+    } else if (item->endNode == aParent && item->endOffset > aOffset) {
+      item->endOffset += (int32_t)aNodeOrigLen - 1;
     }
-    else if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
-      item->endOffset += (int32_t)aNodeOrigLen-1;
   }
   return NS_OK;
 }
 
+nsresult
+nsRangeUpdater::DidRemoveContainer(nsIDOMNode* aNode, nsIDOMNode* aParent,
+                                   int32_t aOffset, uint32_t aNodeOrigLen)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
+  return DidRemoveContainer(node, parent, aOffset, aNodeOrigLen);
+}
+
 
 nsresult
 nsRangeUpdater::WillInsertContainer()
 {
   if (mLock) return NS_ERROR_UNEXPECTED;  
   mLock = true;
   return NS_OK;
 }
@@ -604,65 +656,61 @@ void
 nsRangeUpdater::DidMoveNode(nsINode* aOldParent, int32_t aOldOffset,
                             nsINode* aNewParent, int32_t aNewOffset)
 {
   MOZ_ASSERT(aOldParent);
   MOZ_ASSERT(aNewParent);
   NS_ENSURE_TRUE_VOID(mLock);
   mLock = false;
 
-  nsIDOMNode* oldParent = aOldParent->AsDOMNode();
-  nsIDOMNode* newParent = aNewParent->AsDOMNode();
-
   for (uint32_t i = 0, count = mArray.Length(); i < count; ++i) {
     nsRangeStore* item = mArray[i];
     NS_ENSURE_TRUE_VOID(item);
     
     // like a delete in aOldParent
-    if (item->startNode == oldParent && item->startOffset > aOldOffset) {
+    if (item->startNode == aOldParent && item->startOffset > aOldOffset) {
       item->startOffset--;
     }
-    if (item->endNode == oldParent && item->endOffset > aOldOffset) {
+    if (item->endNode == aOldParent && item->endOffset > aOldOffset) {
       item->endOffset--;
     }
       
     // and like an insert in aNewParent
-    if (item->startNode == newParent && item->startOffset > aNewOffset) {
+    if (item->startNode == aNewParent && item->startOffset > aNewOffset) {
       item->startOffset++;
     }
-    if (item->endNode == newParent && item->endOffset > aNewOffset) {
+    if (item->endNode == aNewParent && item->endOffset > aNewOffset) {
       item->endOffset++;
     }
   }
 }
 
 
 
 /***************************************************************************
  * helper class for nsSelectionState.  nsRangeStore stores range endpoints.
  */
 
-  // DEBUG: int32_t nsRangeStore::n = 0;
-
 nsRangeStore::nsRangeStore() 
 { 
-  // DEBUG: n++;  printf("range store alloc count=%d\n", n); 
 }
 nsRangeStore::~nsRangeStore()
 {
-  // DEBUG: n--;  printf("range store alloc count=%d\n", n); 
 }
 
-nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
+void
+nsRangeStore::StoreRange(nsRange* aRange)
 {
-  NS_ENSURE_TRUE(aRange, NS_ERROR_NULL_POINTER);
-  aRange->GetStartContainer(getter_AddRefs(startNode));
-  aRange->GetEndContainer(getter_AddRefs(endNode));
-  aRange->GetStartOffset(&startOffset);
-  aRange->GetEndOffset(&endOffset);
-  return NS_OK;
+  MOZ_ASSERT(aRange);
+  startNode = aRange->GetStartParent();
+  startOffset = aRange->StartOffset();
+  endNode = aRange->GetEndParent();
+  endOffset = aRange->EndOffset();
 }
 
-nsresult nsRangeStore::GetRange(nsRange** outRange)
+already_AddRefed<nsRange>
+nsRangeStore::GetRange()
 {
-  return nsRange::CreateRange(startNode, startOffset, endNode, endOffset,
-                              outRange);
+  nsRefPtr<nsRange> range = new nsRange(startNode);
+  nsresult res = range->Set(startNode, startOffset, endNode, endOffset);
+  NS_ENSURE_SUCCESS(res, nullptr);
+  return range.forget();
 }
--- a/editor/libeditor/base/nsSelectionState.h
+++ b/editor/libeditor/base/nsSelectionState.h
@@ -34,26 +34,25 @@ struct nsRangeStore MOZ_FINAL
 {
   nsRangeStore();
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~nsRangeStore();
 
 public:
-  nsresult StoreRange(nsIDOMRange *aRange);
-  nsresult GetRange(nsRange** outRange);
+  void StoreRange(nsRange* aRange);
+  already_AddRefed<nsRange> GetRange();
 
   NS_INLINE_DECL_REFCOUNTING(nsRangeStore)
         
-  nsCOMPtr<nsIDOMNode> startNode;
-  int32_t              startOffset;
-  nsCOMPtr<nsIDOMNode> endNode;
-  int32_t              endOffset;
-  // DEBUG:   static int32_t n;
+  nsCOMPtr<nsINode> startNode;
+  int32_t           startOffset;
+  nsCOMPtr<nsINode> endNode;
+  int32_t           endOffset;
 };
 
 class nsSelectionState
 {
   public:
       
     nsSelectionState();
     ~nsSelectionState();
@@ -85,32 +84,49 @@ class nsRangeUpdater
     nsresult RegisterSelectionState(nsSelectionState &aSelState);
     nsresult DropSelectionState(nsSelectionState &aSelState);
     
     // editor selection gravity routines.  Note that we can't always depend on
     // DOM Range gravity to do what we want to the "real" selection.  For instance,
     // if you move a node, that corresponds to deleting it and reinserting it.
     // DOM Range gravity will promote the selection out of the node on deletion,
     // which is not what you want if you know you are reinserting it.
+    nsresult SelAdjCreateNode(nsINode* aParent, int32_t aPosition);
     nsresult SelAdjCreateNode(nsIDOMNode *aParent, int32_t aPosition);
+    nsresult SelAdjInsertNode(nsINode* aParent, int32_t aPosition);
     nsresult SelAdjInsertNode(nsIDOMNode *aParent, int32_t aPosition);
+    void     SelAdjDeleteNode(nsINode* aNode);
     void     SelAdjDeleteNode(nsIDOMNode *aNode);
+    nsresult SelAdjSplitNode(nsINode* aOldRightNode, int32_t aOffset,
+                             nsINode* aNewLeftNode);
     nsresult SelAdjSplitNode(nsIDOMNode *aOldRightNode, int32_t aOffset, nsIDOMNode *aNewLeftNode);
+    nsresult SelAdjJoinNodes(nsINode* aLeftNode,
+                             nsINode* aRightNode,
+                             nsINode* aParent,
+                             int32_t aOffset,
+                             int32_t aOldLeftNodeLength);
     nsresult SelAdjJoinNodes(nsIDOMNode *aLeftNode, 
                              nsIDOMNode *aRightNode, 
                              nsIDOMNode *aParent, 
                              int32_t aOffset,
                              int32_t aOldLeftNodeLength);
+    nsresult SelAdjInsertText(nsIContent* aTextNode, int32_t aOffset,
+                              const nsAString &aString);
     nsresult SelAdjInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, const nsAString &aString);
+    nsresult SelAdjDeleteText(nsIContent* aTextNode, int32_t aOffset,
+                              int32_t aLength);
     nsresult SelAdjDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength);
     // the following gravity routines need will/did sandwiches, because the other gravity
     // routines will be called inside of these sandwiches, but should be ignored.
     nsresult WillReplaceContainer();
+    nsresult DidReplaceContainer(nsINode* aOriginalNode, nsINode* aNewNode);
     nsresult DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode);
     nsresult WillRemoveContainer();
+    nsresult DidRemoveContainer(nsINode* aNode, nsINode* aParent,
+                                int32_t aOffset, uint32_t aNodeOrigLen);
     nsresult DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aOffset, uint32_t aNodeOrigLen);
     nsresult WillInsertContainer();
     nsresult DidInsertContainer();
     void WillMoveNode();
     void DidMoveNode(nsINode* aOldParent, int32_t aOldOffset,
                      nsINode* aNewParent, int32_t aNewOffset);
   protected:    
     nsTArray<nsRefPtr<nsRangeStore> > mArray;
@@ -122,37 +138,60 @@ class nsRangeUpdater
  * helper class for using nsSelectionState.  stack based class for doing
  * preservation of dom points across editor actions
  */
 
 class MOZ_STACK_CLASS nsAutoTrackDOMPoint
 {
   private:
     nsRangeUpdater &mRU;
-    nsCOMPtr<nsIDOMNode> *mNode;
-    int32_t *mOffset;
+    // Allow tracking either nsIDOMNode or nsINode until nsIDOMNode is gone
+    nsCOMPtr<nsINode>* mNode;
+    nsCOMPtr<nsIDOMNode>* mDOMNode;
+    int32_t* mOffset;
     nsRefPtr<nsRangeStore> mRangeItem;
   public:
-    nsAutoTrackDOMPoint(nsRangeUpdater &aRangeUpdater, nsCOMPtr<nsIDOMNode> *aNode, int32_t *aOffset) :
-    mRU(aRangeUpdater)
-    ,mNode(aNode)
-    ,mOffset(aOffset)
+    nsAutoTrackDOMPoint(nsRangeUpdater &aRangeUpdater,
+                        nsCOMPtr<nsINode>* aNode, int32_t* aOffset)
+      : mRU(aRangeUpdater)
+      , mNode(aNode)
+      , mDOMNode(nullptr)
+      , mOffset(aOffset)
     {
       mRangeItem = new nsRangeStore();
       mRangeItem->startNode = *mNode;
       mRangeItem->endNode = *mNode;
       mRangeItem->startOffset = *mOffset;
       mRangeItem->endOffset = *mOffset;
       mRU.RegisterRangeItem(mRangeItem);
     }
-    
+
+    nsAutoTrackDOMPoint(nsRangeUpdater &aRangeUpdater,
+                        nsCOMPtr<nsIDOMNode>* aNode, int32_t* aOffset)
+      : mRU(aRangeUpdater)
+      , mNode(nullptr)
+      , mDOMNode(aNode)
+      , mOffset(aOffset)
+    {
+      mRangeItem = new nsRangeStore();
+      mRangeItem->startNode = do_QueryInterface(*mDOMNode);
+      mRangeItem->endNode = do_QueryInterface(*mDOMNode);
+      mRangeItem->startOffset = *mOffset;
+      mRangeItem->endOffset = *mOffset;
+      mRU.RegisterRangeItem(mRangeItem);
+    }
+
     ~nsAutoTrackDOMPoint()
     {
       mRU.DropRangeItem(mRangeItem);
-      *mNode  = mRangeItem->startNode;
+      if (mNode) {
+        *mNode = mRangeItem->startNode;
+      } else {
+        *mDOMNode = GetAsDOMNode(mRangeItem->startNode);
+      }
       *mOffset = mRangeItem->startOffset;
     }
 };
 
 
 
 /***************************************************************************
  * another helper class for nsSelectionState.  stack based class for doing
--- a/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
+++ b/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
@@ -44,16 +44,17 @@
 #include "nsUnicharUtils.h"
 #include "nscore.h"
 #include "nsContentUtils.h" // for nsAutoScriptBlocker
 
 class nsIDOMEventListener;
 class nsISelection;
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 // retrieve an integer stored into a CSS computed float value
 static int32_t GetCSSFloatValue(nsIDOMCSSStyleDeclaration * aDecl,
                                 const nsAString & aProperty)
 {
   MOZ_ASSERT(aDecl);
 
   nsCOMPtr<nsIDOMCSSValue> value;
@@ -141,24 +142,25 @@ nsHTMLEditor::CreateAnonymousElement(con
   nsCOMPtr<nsIDocument> doc = GetDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
 
   // Get the pres shell
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
 
   // Create a new node through the element factory
-  nsCOMPtr<dom::Element> newContent;
-  nsresult res = CreateHTMLContent(aTag, getter_AddRefs(newContent));
-  NS_ENSURE_SUCCESS(res, res);
+  ErrorResult rv;
+  nsCOMPtr<Element> newContent = CreateHTMLContent(aTag, rv);
+  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
 
   nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newContent);
   NS_ENSURE_TRUE(newElement, NS_ERROR_FAILURE);
 
   // add the "hidden" class if needed
+  nsresult res;
   if (aIsCreatedHidden) {
     res = newElement->SetAttribute(NS_LITERAL_STRING("class"),
                                    NS_LITERAL_STRING("hidden"));
     NS_ENSURE_SUCCESS(res, res);
   }
 
   // add an _moz_anonclass attribute if needed
   if (!aAnonClass.IsEmpty()) {
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -563,20 +563,19 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
           }
           else
           {
             curNode->RemoveChild(child, getter_AddRefs(tmp));
           }
           curNode->GetFirstChild(getter_AddRefs(child));
         }
 
-      }
-      // Check for pre's going into pre's.
-      else if (nsHTMLEditUtils::IsPre(parentBlock) && nsHTMLEditUtils::IsPre(curNode))
-      {
+      } else if (parentBlock && nsHTMLEditUtils::IsPre(parentBlock) &&
+                 nsHTMLEditUtils::IsPre(curNode)) {
+        // Check for pre's going into pre's.
         nsCOMPtr<nsIDOMNode> child, tmp;
         curNode->GetFirstChild(getter_AddRefs(child));
         while (child)
         {
           rv = InsertNodeAtPoint(child, address_of(parentNode), &offsetOfNewNode, true);
           if (NS_FAILED(rv))
             break;
 
@@ -672,28 +671,28 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
         // we are after a break.  Is it visible?  Despite the name, 
         // PriorVisibleNode does not make that determination for breaks.
         // It also may not return the break in visNode.  We have to pull it
         // out of the nsWSRunObject's state.
         if (!IsVisBreak(wsRunObj.mStartReasonNode))
         {
           // don't leave selection past an invisible break;
           // reset {selNode,selOffset} to point before break
-          selNode = GetNodeLocation(wsRunObj.mStartReasonNode, &selOffset);
+          selNode = GetNodeLocation(GetAsDOMNode(wsRunObj.mStartReasonNode), &selOffset);
           // we want to be inside any inline style prior to break
           nsWSRunObject wsRunObj(this, selNode, selOffset);
           wsRunObj.PriorVisibleNode(selNode, selOffset, address_of(visNode),
                                     &outVisOffset, &visType);
           if (visType == WSType::text || visType == WSType::normalWS) {
             selNode = visNode;
             selOffset = outVisOffset;  // PriorVisibleNode already set offset to _after_ the text or ws
           } else if (visType == WSType::special) {
             // prior visible thing is an image or some other non-text thingy.  
             // We want to be right after it.
-            selNode = GetNodeLocation(wsRunObj.mStartReasonNode, &selOffset);
+            selNode = GetNodeLocation(GetAsDOMNode(wsRunObj.mStartReasonNode), &selOffset);
             ++selOffset;
           }
         }
       }
       selection->Collapse(selNode, selOffset);
 
       // if we just pasted a link, discontinue link style
       nsCOMPtr<nsIDOMNode> link;
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -299,36 +299,27 @@ nsHTMLEditRules::BeforeEdit(EditAction a
   if (!mActionNesting++)
   {
     // clear our flag about if just deleted a range
     mDidRangedDelete = false;
     
     // remember where our selection was before edit action took place:
     
     // get selection
-    nsCOMPtr<nsISelection> selection;
-    NS_ENSURE_STATE(mHTMLEditor);
-    nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
-    NS_ENSURE_SUCCESS(res, res);
-  
-    // get the selection start location
-    nsCOMPtr<nsIDOMNode> selStartNode, selEndNode;
-    int32_t selOffset;
-    NS_ENSURE_STATE(mHTMLEditor);
-    res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selOffset);
-    NS_ENSURE_SUCCESS(res, res);
-    mRangeItem->startNode = selStartNode;
-    mRangeItem->startOffset = selOffset;
-
-    // get the selection end location
-    NS_ENSURE_STATE(mHTMLEditor);
-    res = mHTMLEditor->GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selOffset);
-    NS_ENSURE_SUCCESS(res, res);
-    mRangeItem->endNode = selEndNode;
-    mRangeItem->endOffset = selOffset;
+    NS_ENSURE_STATE(mHTMLEditor);
+    nsRefPtr<Selection> selection = mHTMLEditor->GetSelection();
+
+    // get the selection location
+    NS_ENSURE_STATE(selection->GetRangeCount());
+    mRangeItem->startNode = selection->GetRangeAt(0)->GetStartParent();
+    mRangeItem->startOffset = selection->GetRangeAt(0)->StartOffset();
+    mRangeItem->endNode = selection->GetRangeAt(0)->GetEndParent();
+    mRangeItem->endOffset = selection->GetRangeAt(0)->EndOffset();
+    nsCOMPtr<nsIDOMNode> selStartNode = GetAsDOMNode(mRangeItem->startNode);
+    nsCOMPtr<nsIDOMNode> selEndNode = GetAsDOMNode(mRangeItem->endNode);
 
     // register this range with range updater to track this as we perturb the doc
     NS_ENSURE_STATE(mHTMLEditor);
     (mHTMLEditor->mRangeUpdater).RegisterRangeItem(mRangeItem);
 
     // clear deletion state bool
     mDidDeleteSelection = false;
     
@@ -347,17 +338,17 @@ nsHTMLEditRules::BeforeEdit(EditAction a
     // remember current inline styles for deletion and normal insertion operations
     if (action == EditAction::insertText ||
         action == EditAction::insertIMEText ||
         action == EditAction::deleteSelection ||
         IsStyleCachePreservingAction(action)) {
       nsCOMPtr<nsIDOMNode> selNode = selStartNode;
       if (aDirection == nsIEditor::eNext)
         selNode = selEndNode;
-      res = CacheInlineStyles(selNode);
+      nsresult res = CacheInlineStyles(selNode);
       NS_ENSURE_SUCCESS(res, res);
     }
 
     // Stabilize the document against contenteditable count changes
     NS_ENSURE_STATE(mHTMLEditor);
     nsCOMPtr<nsIDOMDocument> doc = mHTMLEditor->GetDOMDocument();
     NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
@@ -485,23 +476,23 @@ nsHTMLEditRules::AfterEditInner(EditActi
         (action == EditAction::htmlPaste ||
         (action == EditAction::loadHTML)))
     {
       res = AdjustWhitespace(selection);
       NS_ENSURE_SUCCESS(res, res);
       
       // also do this for original selection endpoints. 
       NS_ENSURE_STATE(mHTMLEditor);
-      nsWSRunObject(mHTMLEditor, mRangeItem->startNode,
+      nsWSRunObject(mHTMLEditor, GetAsDOMNode(mRangeItem->startNode),
                     mRangeItem->startOffset).AdjustWhitespace();
       // we only need to handle old selection endpoint if it was different from start
       if (mRangeItem->startNode != mRangeItem->endNode ||
           mRangeItem->startOffset != mRangeItem->endOffset) {
         NS_ENSURE_STATE(mHTMLEditor);
-        nsWSRunObject(mHTMLEditor, mRangeItem->endNode,
+        nsWSRunObject(mHTMLEditor, GetAsDOMNode(mRangeItem->endNode),
                       mRangeItem->endOffset).AdjustWhitespace();
       }
     }
     
     // if we created a new block, make sure selection lands in it
     if (mNewBlock)
     {
       res = PinSelectionToNewBlock(selection);
@@ -531,17 +522,17 @@ nsHTMLEditRules::AfterEditInner(EditActi
       NS_ENSURE_SUCCESS(res, res);
       ClearCachedStyles();
     }    
   }
 
   NS_ENSURE_STATE(mHTMLEditor);
   
   res = mHTMLEditor->HandleInlineSpellCheck(action, selection, 
-                                            mRangeItem->startNode,
+                                            GetAsDOMNode(mRangeItem->startNode),
                                             mRangeItem->startOffset,
                                             rangeStartParent, rangeStartOffset,
                                             rangeEndParent, rangeEndOffset);
   NS_ENSURE_SUCCESS(res, res);
 
   // detect empty doc
   res = CreateBogusNodeIfNeeded(selection);
   
@@ -1270,18 +1261,17 @@ nsHTMLEditRules::WillInsert(nsISelection
     }
     else {
       NS_ENSURE_STATE(mHTMLEditor);
       block1 = mHTMLEditor->GetBlockNodeParent(selNode);
     }
     NS_ENSURE_STATE(mHTMLEditor);
     block2 = mHTMLEditor->GetBlockNodeParent(priorNode);
   
-    if (block1 == block2)
-    {
+    if (block1 && block1 == block2) {
       // if we are here then the selection is right after a mozBR
       // that is in the same block as the selection.  We need to move
       // the selection start to be before the mozBR.
       selNode = nsEditor::GetNodeLocation(priorNode, &selOffset);
       res = aSelection->Collapse(selNode,selOffset);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
@@ -1485,18 +1475,21 @@ nsHTMLEditRules::WillInsertText(EditActi
         {
           res = wsObj.InsertText(spacesStr, address_of(curNode), &curOffset, doc);
           NS_ENSURE_SUCCESS(res, res);
           pos++;
         }
         // is it a return?
         else if (subStr.Equals(newlineStr))
         {
-          res = wsObj.InsertBreak(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
-          NS_ENSURE_SUCCESS(res, res);
+          nsCOMPtr<nsINode> node(do_QueryInterface(curNode));
+          nsCOMPtr<Element> br =
+            wsObj.InsertBreak(address_of(node), &curOffset, nsIEditor::eNone);
+          NS_ENSURE_TRUE(br, NS_ERROR_FAILURE);
+          curNode = GetAsDOMNode(node);
           pos++;
         }
         else
         {
           res = wsObj.InsertText(subStr, address_of(curNode), &curOffset, doc);
           NS_ENSURE_SUCCESS(res, res);
         }
         NS_ENSURE_SUCCESS(res, res);
@@ -1701,18 +1694,22 @@ nsHTMLEditRules::StandardBreakImpl(nsIDO
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->SplitNodeDeep(linkNode, node, aOffset,
                                        &newOffset, true);
       NS_ENSURE_SUCCESS(res, res);
       // reset {node,aOffset} to the point where link was split
       node = linkParent;
       aOffset = newOffset;
     }
-    res = wsObj.InsertBreak(address_of(node), &aOffset,
-                            address_of(brNode), nsIEditor::eNone);
+    nsCOMPtr<nsINode> node_ = do_QueryInterface(node);
+    nsCOMPtr<Element> br =
+      wsObj.InsertBreak(address_of(node_), &aOffset, nsIEditor::eNone);
+    node = GetAsDOMNode(node_);
+    brNode = GetAsDOMNode(br);
+    NS_ENSURE_TRUE(brNode, NS_ERROR_FAILURE);
   }
   NS_ENSURE_SUCCESS(res, res);
   node = nsEditor::GetNodeLocation(brNode, &aOffset);
   NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
   if (bAfterBlock && bBeforeBlock) {
     // we just placed a br between block boundaries.  This is the one case
     // where we want the selection to be before the br we just placed, as the
     // br will be on a new line, rather than at end of prior line.
@@ -2387,18 +2384,17 @@ nsHTMLEditRules::WillDeleteSelection(Sel
       if (IsBlockNode(endNode))
         rightParent = endNode;
       else {
         NS_ENSURE_STATE(mHTMLEditor);
         rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
       }
         
       // are endpoint block parents the same?  use default deletion
-      if (leftParent == rightParent) 
-      {
+      if (leftParent && leftParent == rightParent) {
         NS_ENSURE_STATE(mHTMLEditor);
         res = mHTMLEditor->DeleteSelectionImpl(aAction, aStripWrappers);
       }
       else
       {
         // deleting across blocks
         // are the blocks of same type?
         NS_ENSURE_STATE(leftParent && rightParent);
@@ -2687,16 +2683,17 @@ nsHTMLEditRules::JoinBlocks(nsIDOMNode *
     nsCOMPtr<nsIDOMNode> realLeft = mHTMLEditor->GetBlockNodeParent(aLeftBlock);
     aLeftBlock = realLeft;
   }
   if (nsHTMLEditUtils::IsHR(aRightBlock)) {
     NS_ENSURE_STATE(mHTMLEditor);
     nsCOMPtr<nsIDOMNode> realRight = mHTMLEditor->GetBlockNodeParent(aRightBlock);
     aRightBlock = realRight;
   }
+  NS_ENSURE_STATE(aLeftBlock && aRightBlock);
 
   // bail if both blocks the same
   if (aLeftBlock == aRightBlock) {
     *aCanceled = true;
     return NS_OK;
   }
   
   // Joining a list item to its parent is a NOP.
@@ -2746,26 +2743,31 @@ nsHTMLEditRules::JoinBlocks(nsIDOMNode *
 
   // theOffset below is where you find yourself in aRightBlock when you traverse upwards
   // from aLeftBlock
   if (nsEditorUtils::IsDescendantOf(aLeftBlock, aRightBlock, &rightOffset)) {
     // tricky case.  left block is inside right block.
     // Do ws adjustment.  This just destroys non-visible ws at boundaries we will be joining.
     rightOffset++;
     NS_ENSURE_STATE(mHTMLEditor);
+    nsCOMPtr<nsINode> leftBlock(do_QueryInterface(aLeftBlock));
     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
-                                            address_of(aLeftBlock),
-                                            nsWSRunObject::kBlockEnd);
-    NS_ENSURE_SUCCESS(res, res);
-    NS_ENSURE_STATE(mHTMLEditor);
-    res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
-                                            address_of(aRightBlock),
-                                            nsWSRunObject::kAfterBlock,
-                                            &rightOffset);
-    NS_ENSURE_SUCCESS(res, res);
+                                            nsWSRunObject::kBlockEnd,
+                                            leftBlock);
+    NS_ENSURE_SUCCESS(res, res);
+
+    {
+      nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
+                                  address_of(aRightBlock), &rightOffset);
+      nsCOMPtr<nsINode> rightBlock(do_QueryInterface(aRightBlock));
+      res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
+                                              nsWSRunObject::kAfterBlock,
+                                              rightBlock, rightOffset);
+      NS_ENSURE_SUCCESS(res, res);
+    }
     // Do br adjustment.
     nsCOMPtr<nsIDOMNode> brNode;
     res = CheckForInvisibleBR(aLeftBlock, kBlockEnd, address_of(brNode));
     NS_ENSURE_SUCCESS(res, res);
     if (bMergeLists)
     {
       // idea here is to take all children in  rightList that are past
       // theOffset, and pull them into leftlist.
@@ -2791,26 +2793,31 @@ nsHTMLEditRules::JoinBlocks(nsIDOMNode *
     NS_ENSURE_STATE(mHTMLEditor);
     if (brNode) mHTMLEditor->DeleteNode(brNode);
   // theOffset below is where you find yourself in aLeftBlock when you traverse upwards
   // from aRightBlock
   } else if (nsEditorUtils::IsDescendantOf(aRightBlock, aLeftBlock, &leftOffset)) {
     // tricky case.  right block is inside left block.
     // Do ws adjustment.  This just destroys non-visible ws at boundaries we will be joining.
     NS_ENSURE_STATE(mHTMLEditor);
+    nsCOMPtr<nsINode> rightBlock(do_QueryInterface(aRightBlock));
     res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
-                                            address_of(aRightBlock),
-                                            nsWSRunObject::kBlockStart);
-    NS_ENSURE_SUCCESS(res, res);
-    NS_ENSURE_STATE(mHTMLEditor);
-    res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
-                                            address_of(aLeftBlock),
-                                            nsWSRunObject::kBeforeBlock,
-                                            &leftOffset);
-    NS_ENSURE_SUCCESS(res, res);
+                                            nsWSRunObject::kBlockStart,
+                                            rightBlock);
+    NS_ENSURE_SUCCESS(res, res);
+    NS_ENSURE_STATE(mHTMLEditor);
+    {
+      nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater,
+                                  address_of(aLeftBlock), &leftOffset);
+      nsCOMPtr<nsINode> leftBlock(do_QueryInterface(aLeftBlock));
+      res = nsWSRunObject::ScrubBlockBoundary(mHTMLEditor,
+                                              nsWSRunObject::kBeforeBlock,
+                                              leftBlock, leftOffset);
+      NS_ENSURE_SUCCESS(res, res);
+    }
     // Do br adjustment.
     nsCOMPtr<nsIDOMNode> brNode;
     res = CheckForInvisibleBR(aLeftBlock, kBeforeBlock, address_of(brNode),
                               leftOffset);
     NS_ENSURE_SUCCESS(res, res);
     if (bMergeLists)
     {
       res = MoveContents(rightList, leftList, &leftOffset);
@@ -5084,28 +5091,30 @@ nsHTMLEditRules::CheckForEmptyBlock(nsID
   // Note: do NOT delete table elements this way.
   nsresult res = NS_OK;
   nsCOMPtr<nsIDOMNode> block, emptyBlock;
   if (IsBlockNode(aStartNode)) 
     block = aStartNode;
   else
     block = mHTMLEditor->GetBlockNodeParent(aStartNode);
   bool bIsEmptyNode;
-  if (block != aBodyNode)  // efficiency hack. avoiding IsEmptyNode() call when in body
-  {
+  if (block && block != aBodyNode) {
+    // efficiency hack. avoiding IsEmptyNode() call when in body
     NS_ENSURE_STATE(mHTMLEditor);
     res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
     NS_ENSURE_SUCCESS(res, res);
-    while (bIsEmptyNode && !nsHTMLEditUtils::IsTableElement(block) && (block != aBodyNode))
-    {
+    while (block && bIsEmptyNode && !nsHTMLEditUtils::IsTableElement(block) &&
+           block != aBodyNode) {
       emptyBlock = block;
       block = mHTMLEditor->GetBlockNodeParent(emptyBlock);
       NS_ENSURE_STATE(mHTMLEditor);
-      res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
-      NS_ENSURE_SUCCESS(res, res);
+      if (block) {
+        res = mHTMLEditor->IsEmptyNode(block, &bIsEmptyNode, true, false);
+        NS_ENSURE_SUCCESS(res, res);
+      }
     }
   }
 
   nsCOMPtr<nsIContent> emptyContent = do_QueryInterface(emptyBlock);
   if (emptyBlock && emptyContent->IsEditable())
   {
     int32_t offset;
     nsCOMPtr<nsIDOMNode> blockParent = nsEditor::GetNodeLocation(emptyBlock, &offset);
@@ -5189,17 +5198,17 @@ nsHTMLEditRules::CheckForInvisibleBR(nsI
     // we'll check everything to the left of the input position
     testOffset = aOffset;
   }
 
   if (runTest)
   {
     nsWSRunObject wsTester(mHTMLEditor, testNode, testOffset);
     if (WSType::br == wsTester.mStartReason) {
-      *outBRNode = wsTester.mStartReasonNode;
+      *outBRNode = GetAsDOMNode(wsTester.mStartReasonNode);
     }
   }
 
   return NS_OK;
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
@@ -5279,16 +5288,17 @@ nsHTMLEditRules::ExpandSelectionForDelet
   res = range->GetEndOffset(&selEndOffset);
   NS_ENSURE_SUCCESS(res, res);
 
   // find current selection common block parent
   res = range->GetCommonAncestorContainer(getter_AddRefs(selCommon));
   NS_ENSURE_SUCCESS(res, res);
   if (!IsBlockNode(selCommon))
     selCommon = nsHTMLEditor::GetBlockNodeParent(selCommon);
+  NS_ENSURE_STATE(selCommon);
 
   // set up for loops and cache our root element
   bool stillLooking = true;
   nsCOMPtr<nsIDOMNode> visNode, firstBRParent;
   int32_t visOffset=0, firstBROffset=0;
   WSType wsType;
   nsCOMPtr<nsIContent> rootContent = mHTMLEditor->GetActiveEditingHost();
   nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(rootContent);
@@ -5300,25 +5310,24 @@ nsHTMLEditRules::ExpandSelectionForDelet
     while (stillLooking)
     {
       nsWSRunObject wsObj(mHTMLEditor, selStartNode, selStartOffset);
       wsObj.PriorVisibleNode(selStartNode, selStartOffset, address_of(visNode),
                              &visOffset, &wsType);
       if (wsType == WSType::thisBlock) {
         // we want to keep looking up.  But stop if we are crossing table element
         // boundaries, or if we hit the root.
-        if ( nsHTMLEditUtils::IsTableElement(wsObj.mStartReasonNode) ||
-            (selCommon == wsObj.mStartReasonNode)                    ||
-            (rootElement == wsObj.mStartReasonNode) )
-        {
+        if (nsHTMLEditUtils::IsTableElement(wsObj.mStartReasonNode) ||
+            selCommon == GetAsDOMNode(wsObj.mStartReasonNode) ||
+            rootElement == GetAsDOMNode(wsObj.mStartReasonNode)) {
           stillLooking = false;
         }
         else
         { 
-          selStartNode = nsEditor::GetNodeLocation(wsObj.mStartReasonNode,
+          selStartNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsObj.mStartReasonNode),
                                                    &selStartOffset);
         }
       }
       else
       {
         stillLooking = false;
       }
     }
@@ -5340,31 +5349,30 @@ nsHTMLEditRules::ExpandSelectionForDelet
         }
         else
         { 
           if (!firstBRParent)
           {
             firstBRParent = selEndNode;
             firstBROffset = selEndOffset;
           }
-          selEndNode = nsEditor::GetNodeLocation(wsObj.mEndReasonNode, &selEndOffset);
+          selEndNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsObj.mEndReasonNode), &selEndOffset);
           ++selEndOffset;
         }
       } else if (wsType == WSType::thisBlock) {
         // we want to keep looking up.  But stop if we are crossing table element
         // boundaries, or if we hit the root.
-        if ( nsHTMLEditUtils::IsTableElement(wsObj.mEndReasonNode) ||
-            (selCommon == wsObj.mEndReasonNode)                    ||
-            (rootElement == wsObj.mEndReasonNode) )
-        {
+        if (nsHTMLEditUtils::IsTableElement(wsObj.mEndReasonNode) ||
+            selCommon == GetAsDOMNode(wsObj.mEndReasonNode) ||
+            rootElement == GetAsDOMNode(wsObj.mEndReasonNode)) {
           stillLooking = false;
         }
         else
         { 
-          selEndNode = nsEditor::GetNodeLocation(wsObj.mEndReasonNode, &selEndOffset);
+          selEndNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsObj.mEndReasonNode), &selEndOffset);
           ++selEndOffset;
         }
        }
       else
       {
         stillLooking = false;
       }
     }
@@ -5390,17 +5398,20 @@ nsHTMLEditRules::ExpandSelectionForDelet
     nsRefPtr<nsRange> range = new nsRange(node);
     res = range->SetStart(selStartNode, selStartOffset);
     NS_ENSURE_SUCCESS(res, res);
     res = range->SetEnd(selEndNode, selEndOffset);
     NS_ENSURE_SUCCESS(res, res);
     
     // check if block is entirely inside range
     nsCOMPtr<nsIContent> brContentBlock = do_QueryInterface(brBlock);
-    res = nsRange::CompareNodeToRange(brContentBlock, range, &nodeBefore, &nodeAfter);
+    if (brContentBlock) {
+      res = nsRange::CompareNodeToRange(brContentBlock, range, &nodeBefore,
+                                        &nodeAfter);
+    }
     
     // if block isn't contained, forgo grabbing the br in the expanded selection
     if (nodeBefore || nodeAfter)
       doEndExpansion = false;
   }
   if (doEndExpansion)
   {
     res = aSelection->Extend(selEndNode, selEndOffset);
@@ -5474,17 +5485,17 @@ nsHTMLEditRules::NormalizeSelection(nsIS
   // it would visibly change maening of users selection
   wsEndObj.PriorVisibleNode(endNode, endOffset, address_of(someNode),
                             &offset, &wsType);
   if (wsType != WSType::text && wsType != WSType::normalWS) {
     // eThisBlock and eOtherBlock conveniently distinquish cases
     // of going "down" into a block and "up" out of a block.
     if (wsEndObj.mStartReason == WSType::otherBlock) {
       // endpoint is just after the close of a block.
-      nsCOMPtr<nsIDOMNode> child = mHTMLEditor->GetRightmostChild(wsEndObj.mStartReasonNode, true);
+      nsCOMPtr<nsIDOMNode> child = mHTMLEditor->GetRightmostChild(GetAsDOMNode(wsEndObj.mStartReasonNode), true);
       if (child)
       {
         newEndNode = nsEditor::GetNodeLocation(child, &newEndOffset);
         ++newEndOffset; // offset *after* child
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsEndObj.mStartReason == WSType::thisBlock) {
       // endpoint is just after start of this block
@@ -5494,34 +5505,34 @@ nsHTMLEditRules::NormalizeSelection(nsIS
       if (child)
       {
         newEndNode = nsEditor::GetNodeLocation(child, &newEndOffset);
         ++newEndOffset; // offset *after* child
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsEndObj.mStartReason == WSType::br) {
       // endpoint is just after break.  lets adjust it to before it.
-      newEndNode = nsEditor::GetNodeLocation(wsEndObj.mStartReasonNode,
+      newEndNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsEndObj.mStartReasonNode),
                                              &newEndOffset);
     }
   }
   
   
   // similar dealio for start of range
   nsWSRunObject wsStartObj(mHTMLEditor, startNode, startOffset);
   // is there any intervening visible whitespace?  if so we can't push selection past that,
   // it would visibly change maening of users selection
   wsStartObj.NextVisibleNode(startNode, startOffset, address_of(someNode),
                              &offset, &wsType);
   if (wsType != WSType::text && wsType != WSType::normalWS) {
     // eThisBlock and eOtherBlock conveniently distinquish cases
     // of going "down" into a block and "up" out of a block.
     if (wsStartObj.mEndReason == WSType::otherBlock) {
       // startpoint is just before the start of a block.
-      nsCOMPtr<nsIDOMNode> child = mHTMLEditor->GetLeftmostChild(wsStartObj.mEndReasonNode, true);
+      nsCOMPtr<nsIDOMNode> child = mHTMLEditor->GetLeftmostChild(GetAsDOMNode(wsStartObj.mEndReasonNode), true);
       if (child)
       {
         newStartNode = nsEditor::GetNodeLocation(child, &newStartOffset);
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsStartObj.mEndReason == WSType::thisBlock) {
       // startpoint is just before end of this block
       nsCOMPtr<nsIDOMNode> child;
@@ -5529,17 +5540,17 @@ nsHTMLEditRules::NormalizeSelection(nsIS
       res = mHTMLEditor->GetNextHTMLNode(startNode, startOffset, address_of(child));
       if (child)
       {
         newStartNode = nsEditor::GetNodeLocation(child, &newStartOffset);
       }
       // else block is empty - we can leave selection alone here, i think.
     } else if (wsStartObj.mEndReason == WSType::br) {
       // startpoint is just before a break.  lets adjust it to after it.
-      newStartNode = nsEditor::GetNodeLocation(wsStartObj.mEndReasonNode,
+      newStartNode = nsEditor::GetNodeLocation(GetAsDOMNode(wsStartObj.mEndReasonNode),
                                                &newStartOffset);
       ++newStartOffset; // offset *after* break
     }
   }
   
   // there is a demented possiblity we have to check for.  We might have a very strange selection
   // that is not collapsed and yet does not contain any editable content, and satisfies some of the
   // above conditions that cause tweaking.  In this case we don't want to tweak the selection into
@@ -5932,41 +5943,34 @@ nsHTMLEditRules::GetNodesForOperation(ns
     NS_ASSERTION(static_cast<uint32_t>(rangeCount) == rangeItemArray.Length(),
                  "How did that happen?");
 
     // first register ranges for special editor gravity
     for (i = 0; i < rangeCount; i++)
     {
       opRange = inArrayOfRanges[0];
       rangeItemArray[i] = new nsRangeStore();
-      rangeItemArray[i]->StoreRange(opRange);
+      rangeItemArray[i]->StoreRange(static_cast<nsRange*>(opRange.get()));
       NS_ENSURE_STATE(mHTMLEditor);
       mHTMLEditor->mRangeUpdater.RegisterRangeItem(rangeItemArray[i]);
       inArrayOfRanges.RemoveObjectAt(0);
     }    
     // now bust up inlines.  Safe to start at rangeCount-1, since we
     // asserted we have enough items above.
     for (i = rangeCount-1; i >= 0 && NS_SUCCEEDED(res); i--)
     {
       res = BustUpInlinesAtRangeEndpoints(*rangeItemArray[i]);
     } 
     // then unregister the ranges
     for (i = 0; i < rangeCount; i++)
     {
       nsRangeStore* item = rangeItemArray[i];
       NS_ENSURE_STATE(mHTMLEditor);
       mHTMLEditor->mRangeUpdater.DropRangeItem(item);
-      nsRefPtr<nsRange> range;
-      nsresult res2 = item->GetRange(getter_AddRefs(range));
-      opRange = range;
-      if (NS_FAILED(res2) && NS_SUCCEEDED(res)) {
-        // Remember the failure, but keep going so we make sure to unregister
-        // all our range items.
-        res = res2;
-      }
+      opRange = item->GetRange();
       inArrayOfRanges.AppendObject(opRange);
     }
     NS_ENSURE_SUCCESS(res, res);
   }
   // gather up a list of all the nodes
   for (i = 0; i < rangeCount; i++)
   {
     opRange = inArrayOfRanges[i];
@@ -6321,45 +6325,50 @@ nsHTMLEditRules::GetParagraphFormatNodes
 // BustUpInlinesAtRangeEndpoints: 
 //                       
 nsresult 
 nsHTMLEditRules::BustUpInlinesAtRangeEndpoints(nsRangeStore &item)
 {
   nsresult res = NS_OK;
   bool isCollapsed = ((item.startNode == item.endNode) && (item.startOffset == item.endOffset));
 
-  nsCOMPtr<nsIDOMNode> endInline = GetHighestInlineParent(item.endNode);
+  nsCOMPtr<nsIDOMNode> endInline =
+    GetHighestInlineParent(GetAsDOMNode(item.endNode));
   
   // if we have inline parents above range endpoints, split them
   if (endInline && !isCollapsed)
   {
     nsCOMPtr<nsIDOMNode> resultEndNode;
     int32_t resultEndOffset;
     endInline->GetParentNode(getter_AddRefs(resultEndNode));
     NS_ENSURE_STATE(mHTMLEditor);
-    res = mHTMLEditor->SplitNodeDeep(endInline, item.endNode, item.endOffset,
-                          &resultEndOffset, true);
+    res = mHTMLEditor->SplitNodeDeep(endInline, GetAsDOMNode(item.endNode),
+                                     item.endOffset, &resultEndOffset, true);
     NS_ENSURE_SUCCESS(res, res);
     // reset range
-    item.endNode = resultEndNode; item.endOffset = resultEndOffset;
-  }
-
-  nsCOMPtr<nsIDOMNode> startInline = GetHighestInlineParent(item.startNode);
+    item.endNode = do_QueryInterface(resultEndNode);
+    item.endOffset = resultEndOffset;
+  }
+
+  nsCOMPtr<nsIDOMNode> startInline =
+    GetHighestInlineParent(GetAsDOMNode(item.startNode));
 
   if (startInline)
   {
     nsCOMPtr<nsIDOMNode> resultStartNode;
     int32_t resultStartOffset;
     startInline->GetParentNode(getter_AddRefs(resultStartNode));
     NS_ENSURE_STATE(mHTMLEditor);
-    res = mHTMLEditor->SplitNodeDeep(startInline, item.startNode, item.startOffset,
-                          &resultStartOffset, true);
+    res = mHTMLEditor->SplitNodeDeep(startInline, GetAsDOMNode(item.startNode),
+                                     item.startOffset, &resultStartOffset,
+                                     true);
     NS_ENSURE_SUCCESS(res, res);
     // reset range
-    item.startNode = resultStartNode; item.startOffset = resultStartOffset;
+    item.startNode = do_QueryInterface(resultStartNode);
+    item.startOffset = resultStartOffset;
   }
   
   return res;
 }
 
 
 
 ///////////////////////////////////////////////////////////////////////////
@@ -6460,32 +6469,20 @@ nsHTMLEditRules::GetHighestInlineParent(
 //                     of nodes from a point that will be operated on. 
 //                       
 nsresult 
 nsHTMLEditRules::GetNodesFromPoint(::DOMPoint point,
                                    EditAction operation,
                                    nsCOMArray<nsIDOMNode> &arrayOfNodes,
                                    bool dontTouchContent)
 {
-  nsresult res;
-
-  // get our point
-  nsCOMPtr<nsIDOMNode> node;
-  int32_t offset;
-  point.GetPoint(node, offset);
-  
-  // use it to make a range
-  nsCOMPtr<nsINode> nativeNode = do_QueryInterface(node);
-  NS_ENSURE_STATE(nativeNode);
-  nsRefPtr<nsRange> range = new nsRange(nativeNode);
-  res = range->SetStart(node, offset);
-  NS_ENSURE_SUCCESS(res, res);
-  /* SetStart() will also set the end for this new range
-  res = range->SetEnd(node, offset);
-  NS_ENSURE_SUCCESS(res, res); */
+  NS_ENSURE_STATE(point.node);
+  nsRefPtr<nsRange> range = new nsRange(point.node);
+  nsresult res = range->SetStart(point.node, point.offset);
+  NS_ENSURE_SUCCESS(res, res);
   
   // expand the range to include adjacent inlines
   res = PromoteRange(range, operation);
   NS_ENSURE_SUCCESS(res, res);
       
   // make array of ranges
   nsCOMArray<nsIDOMRange> arrayOfRanges;
   
@@ -7195,18 +7192,17 @@ nsHTMLEditRules::RemoveBlockStyle(nsCOMA
           res = RemovePartOfBlock(curBlock, firstNode, lastNode);
           NS_ENSURE_SUCCESS(res, res);
           curBlock = 0;  firstNode = 0;  lastNode = 0;
           // fall out and handle curNode
         }
       }
       NS_ENSURE_STATE(mHTMLEditor);
       curBlock = mHTMLEditor->GetBlockNodeParent(curNode);
-      if (nsHTMLEditUtils::IsFormatNode(curBlock))
-      {
+      if (curBlock && nsHTMLEditUtils::IsFormatNode(curBlock)) {
         firstNode = curNode;  
         lastNode = curNode;
       }
       else
         curBlock = 0;  // not a block kind that we care about.
     }
     else
     { // some node that is already sans block style.  skip over it and
@@ -7927,18 +7923,17 @@ nsHTMLEditRules::AdjustSelection(nsISele
     if (IsBlockNode(selNode)) {
       block = selNode;
     } else {
       NS_ENSURE_STATE(mHTMLEditor);
       block = mHTMLEditor->GetBlockNodeParent(selNode);
     }
     NS_ENSURE_STATE(mHTMLEditor);
     nearBlock = mHTMLEditor->GetBlockNodeParent(nearNode);
-    if (block == nearBlock)
-    {
+    if (block && block == nearBlock) {
       if (nearNode && nsTextEditUtils::IsBreak(nearNode) )
       {   
         NS_ENSURE_STATE(mHTMLEditor);
         if (!mHTMLEditor->IsVisBreak(nearNode))
         {
           // need to insert special moz BR. Why?  Because if we don't
           // the user will see no new line for the break.  Also, things
           // like table cells won't grow in height.
--- a/editor/libeditor/html/nsHTMLEditUtils.cpp
+++ b/editor/libeditor/html/nsHTMLEditUtils.cpp
@@ -229,22 +229,28 @@ nsHTMLEditUtils::IsTableElementButNotTab
       || (nodeAtom == nsEditProperty::tfoot)
       || (nodeAtom == nsEditProperty::tbody)
       || (nodeAtom == nsEditProperty::caption);
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // IsTable: true if node an html table
 //                  
-bool 
+bool
 nsHTMLEditUtils::IsTable(nsIDOMNode* aNode)
 {
   return nsEditor::NodeIsType(aNode, nsEditProperty::table);
 }
 
+bool
+nsHTMLEditUtils::IsTable(nsINode* aNode)
+{
+  return aNode && aNode->IsElement() && aNode->Tag() == nsGkAtoms::table;
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // IsTableRow: true if node an html tr
 //                  
 bool 
 nsHTMLEditUtils::IsTableRow(nsIDOMNode* aNode)
 {
   return nsEditor::NodeIsType(aNode, nsEditProperty::tr);
 }
@@ -354,23 +360,32 @@ bool
 nsHTMLEditUtils::IsImage(nsIDOMNode* aNode)
 {
   return nsEditor::NodeIsType(aNode, nsEditProperty::img);
 }
 
 bool 
 nsHTMLEditUtils::IsLink(nsIDOMNode *aNode)
 {
-  NS_ENSURE_TRUE(aNode, false);
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  return node && IsLink(node);
+}
+
+bool
+nsHTMLEditUtils::IsLink(nsINode* aNode)
+{
+  MOZ_ASSERT(aNode);
+
   nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aNode);
   if (anchor)
   {
     nsAutoString tmpText;
-    if (NS_SUCCEEDED(anchor->GetHref(tmpText)) && !tmpText.IsEmpty())
+    if (NS_SUCCEEDED(anchor->GetHref(tmpText)) && !tmpText.IsEmpty()) {
       return true;
+    }
   }
   return false;
 }
 
 bool 
 nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode *aNode)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
--- a/editor/libeditor/html/nsHTMLEditUtils.h
+++ b/editor/libeditor/html/nsHTMLEditUtils.h
@@ -24,16 +24,17 @@ public:
   static bool IsFormatNode(nsIDOMNode *aNode);
   static bool IsNodeThatCanOutdent(nsIDOMNode *aNode);
   static bool IsHeader(nsIDOMNode *aNode);
   static bool IsParagraph(nsIDOMNode *aNode);
   static bool IsHR(nsIDOMNode *aNode);
   static bool IsListItem(nsINode* aNode);
   static bool IsListItem(nsIDOMNode *aNode);
   static bool IsTable(nsIDOMNode *aNode);
+  static bool IsTable(nsINode* aNode);
   static bool IsTableRow(nsIDOMNode *aNode);
   static bool IsTableElement(nsINode* aNode);
   static bool IsTableElement(nsIDOMNode *aNode);
   static bool IsTableElementButNotTable(nsINode* aNode);
   static bool IsTableElementButNotTable(nsIDOMNode *aNode);
   static bool IsTableCell(nsINode* node);
   static bool IsTableCell(nsIDOMNode *aNode);
   static bool IsTableCellOrCaption(nsIDOMNode *aNode);
@@ -41,16 +42,17 @@ public:
   static bool IsList(nsIDOMNode *aNode);
   static bool IsOrderedList(nsIDOMNode *aNode);
   static bool IsUnorderedList(nsIDOMNode *aNode);
   static bool IsBlockquote(nsIDOMNode *aNode);
   static bool IsPre(nsIDOMNode *aNode);
   static bool IsAnchor(nsIDOMNode *aNode);
   static bool IsImage(nsIDOMNode *aNode);
   static bool IsLink(nsIDOMNode *aNode);
+  static bool IsLink(nsINode* aNode);
   static bool IsNamedAnchor(nsINode* aNode);
   static bool IsNamedAnchor(nsIDOMNode *aNode);
   static bool IsDiv(nsIDOMNode *aNode);
   static bool IsMozDiv(nsIDOMNode *aNode);
   static bool IsMailCite(nsINode* aNode);
   static bool IsMailCite(nsIDOMNode *aNode);
   static bool IsFormWidget(nsINode* aNode);
   static bool IsFormWidget(nsIDOMNode *aNode);
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -41,17 +41,16 @@
 #include "nsIDOMStyleSheet.h"
 
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMRange.h"
 #include "nsISupportsArray.h"
 #include "nsContentUtils.h"
 #include "nsIDocumentEncoder.h"
-#include "nsIDOMDocumentFragment.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "SetDocTitleTxn.h"
 #include "nsFocusManager.h"
 #include "nsPIDOMWindow.h"
 
 // netwerk
 #include "nsIURI.h"
@@ -65,20 +64,22 @@
 #include "nsEditorUtils.h"
 #include "nsWSRunObject.h"
 #include "nsGkAtoms.h"
 #include "nsIWidget.h"
 
 #include "nsIFrame.h"
 #include "nsIParserService.h"
 #include "mozilla/dom/Selection.h"
+#include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "nsTextFragment.h"
+#include "nsContentList.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::widget;
 
 // Some utilities to handle annoying overloading of "A" tag for link and named anchor
 static char hrefText[] = "href";
 static char anchorTxt[] = "anchor";
@@ -624,47 +625,44 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOM
         return NS_OK; // let it be used for focus switching
       }
 
       if (nativeKeyEvent->IsControl() || nativeKeyEvent->IsAlt() ||
           nativeKeyEvent->IsMeta() || nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
 
-      nsCOMPtr<nsISelection> selection;
-      nsresult rv = GetSelection(getter_AddRefs(selection));
-      NS_ENSURE_SUCCESS(rv, rv);
-      int32_t offset;
-      nsCOMPtr<nsIDOMNode> node, blockParent;
-      rv = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
-      NS_ENSURE_SUCCESS(rv, rv);
-      NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
-
-      bool isBlock = false;
-      NodeIsBlock(node, &isBlock);
-      if (isBlock) {
+      nsRefPtr<Selection> selection = GetSelection();
+      NS_ENSURE_TRUE(selection && selection->RangeCount(), NS_ERROR_FAILURE);
+
+      nsCOMPtr<nsINode> node = selection->GetRangeAt(0)->GetStartParent();
+      MOZ_ASSERT(node);
+
+      nsCOMPtr<nsINode> blockParent;
+      if (IsBlockNode(node)) {
         blockParent = node;
       } else {
         blockParent = GetBlockNodeParent(node);
       }
 
       if (!blockParent) {
         break;
       }
 
       bool handled = false;
+      nsresult rv;
       if (nsHTMLEditUtils::IsTableElement(blockParent)) {
         rv = TabInTable(nativeKeyEvent->IsShift(), &handled);
         if (handled) {
           ScrollSelectionIntoView(false);
         }
       } else if (nsHTMLEditUtils::IsListItem(blockParent)) {
-        rv = Indent(nativeKeyEvent->IsShift() ?
-                      NS_LITERAL_STRING("outdent") :
-                      NS_LITERAL_STRING("indent"));
+        rv = Indent(nativeKeyEvent->IsShift()
+                    ? NS_LITERAL_STRING("outdent")
+                    : NS_LITERAL_STRING("indent"));
         handled = true;
       }
       NS_ENSURE_SUCCESS(rv, rv);
       if (handled) {
         return aKeyEvent->PreventDefault(); // consumed
       }
       if (nativeKeyEvent->IsShift()) {
         return NS_OK; // don't type text for shift tabs
@@ -824,41 +822,46 @@ nsHTMLEditor::SetDocumentTitle(const nsA
   nsAutoTxnsConserveSelection dontChangeSelection(this);
   return nsEditor::DoTransaction(txn);  
 }
 
 /* ------------ Block methods moved from nsEditor -------------- */
 ///////////////////////////////////////////////////////////////////////////
 // GetBlockNodeParent: returns enclosing block level ancestor, if any
 //
+already_AddRefed<Element>
+nsHTMLEditor::GetBlockNodeParent(nsINode* aNode)
+{
+  MOZ_ASSERT(aNode);
+
+  nsCOMPtr<nsINode> p = aNode->GetParentNode();
+
+  while (p) {
+    if (p->IsElement() && NodeIsBlockStatic(p->AsElement())) {
+      return p.forget().downcast<Element>();
+    }
+    p = p->GetParentNode();
+  }
+
+  return nullptr;
+}
+
 already_AddRefed<nsIDOMNode>
 nsHTMLEditor::GetBlockNodeParent(nsIDOMNode *aNode)
 {
-  if (!aNode)
-  {
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+
+  if (!node) {
     NS_NOTREACHED("null node passed to GetBlockNodeParent()");
     return nullptr;
   }
 
-  nsCOMPtr<nsIDOMNode> p;
-  if (NS_FAILED(aNode->GetParentNode(getter_AddRefs(p))))  // no parent, ran off top of tree
-    return nullptr;
-
-  nsCOMPtr<nsIDOMNode> tmp;
-  while (p)
-  {
-    bool isBlock;
-    if (NS_FAILED(NodeIsBlockStatic(p, &isBlock)) || isBlock)
-      break;
-    if (NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
-      break;
-
-    p = tmp;
-  }
-  return p.forget();
+  nsCOMPtr<nsIDOMNode> ret =
+    dont_AddRef(GetAsDOMNode(GetBlockNodeParent(node).take()));
+  return ret.forget();
 }
 
 static const char16_t nbsp = 160;
 
 ///////////////////////////////////////////////////////////////////////////////
 // IsNextCharInNodeWhitespace: checks the adjacent content in the same node to
 //                             see if following selection is whitespace or nbsp
 void
@@ -923,54 +926,71 @@ nsHTMLEditor::IsPrevCharInNodeWhitespace
   }
 }
 
 
 
 /* ------------ End Block methods -------------- */
 
 
-bool nsHTMLEditor::IsVisBreak(nsIDOMNode *aNode)
+bool
+nsHTMLEditor::IsVisBreak(nsINode* aNode)
 {
-  NS_ENSURE_TRUE(aNode, false);
-  if (!nsTextEditUtils::IsBreak(aNode)) 
+  MOZ_ASSERT(aNode);
+  if (!nsTextEditUtils::IsBreak(aNode)) {
     return false;
-  // check if there is a later node in block after br
-  nsCOMPtr<nsIDOMNode> priorNode, nextNode;
-  GetPriorHTMLNode(aNode, address_of(priorNode), true); 
-  GetNextHTMLNode(aNode, address_of(nextNode), true); 
-  // if we are next to another break, we are visible
-  if (priorNode && nsTextEditUtils::IsBreak(priorNode))
+  }
+  // Check if there is a later node in block after br
+  nsCOMPtr<nsINode> priorNode = GetPriorHTMLNode(aNode, true);
+  if (priorNode && nsTextEditUtils::IsBreak(priorNode)) {
     return true;
-  if (nextNode && nsTextEditUtils::IsBreak(nextNode))
+  }
+  nsCOMPtr<nsINode> nextNode = GetNextHTMLNode(aNode, true);
+  if (nextNode && nsTextEditUtils::IsBreak(nextNode)) {
     return true;
+  }
   
-  // if we are right before block boundary, then br not visible
-  NS_ENSURE_TRUE(nextNode, false);  // this break is trailer in block, it's not visible
-  if (IsBlockNode(nextNode))
-    return false; // break is right before a block, it's not visible
+  // If we are right before block boundary, then br not visible
+  if (!nextNode) {
+    // This break is trailer in block, it's not visible
+    return false;
+  }
+  if (IsBlockNode(nextNode)) {
+    // Break is right before a block, it's not visible
+    return false;
+  }
     
-  // sigh.  We have to use expensive whitespace calculation code to 
+  // Sigh.  We have to use expensive whitespace calculation code to 
   // determine what is going on
-  nsCOMPtr<nsIDOMNode> selNode, tmp;
   int32_t selOffset;
-  selNode = GetNodeLocation(aNode, &selOffset);
-  selOffset++; // lets look after the break
-  nsWSRunObject wsObj(this, selNode, selOffset);
+  nsCOMPtr<nsINode> selNode = GetNodeLocation(aNode, &selOffset);
+  // Let's look after the break
+  selOffset++;
+  nsWSRunObject wsObj(this, selNode->AsDOMNode(), selOffset);
   nsCOMPtr<nsIDOMNode> visNode;
-  int32_t visOffset=0;
+  int32_t visOffset = 0;
   WSType visType;
-  wsObj.NextVisibleNode(selNode, selOffset, address_of(visNode), &visOffset, &visType);
+  wsObj.NextVisibleNode(selNode->AsDOMNode(), selOffset, address_of(visNode),
+                        &visOffset, &visType);
   if (visType & WSType::block) {
     return false;
   }
   
   return true;
 }
 
+
+bool
+nsHTMLEditor::IsVisBreak(nsIDOMNode* aNode)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  NS_ENSURE_TRUE(node, false);
+  return IsVisBreak(node);
+}
+
 NS_IMETHODIMP
 nsHTMLEditor::BreakIsVisible(nsIDOMNode *aNode, bool *aIsVisible)
 {
   NS_ENSURE_ARG_POINTER(aNode && aIsVisible);
 
   *aIsVisible = IsVisBreak(aNode);
 
   return NS_OK;
@@ -991,42 +1011,26 @@ nsHTMLEditor::GetIsDocumentEditable(bool
 bool nsHTMLEditor::IsModifiable()
 {
   return !IsReadonly();
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::UpdateBaseURL()
 {
-  nsCOMPtr<nsIDOMDocument> domDoc = GetDOMDocument();
-  NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIDocument> doc = GetDocument();
+  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
   // Look for an HTML <base> tag
-  nsCOMPtr<nsIDOMNodeList> nodeList;
-  nsresult rv = domDoc->GetElementsByTagName(NS_LITERAL_STRING("base"), getter_AddRefs(nodeList));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMNode> baseNode;
-  if (nodeList)
-  {
-    uint32_t count;
-    nodeList->GetLength(&count);
-    if (count >= 1)
-    {
-      rv = nodeList->Item(0, getter_AddRefs(baseNode));
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-  // If no base tag, then set baseURL to the document's URL
-  // This is very important, else relative URLs for links and images are wrong
-  if (!baseNode)
-  {
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
-    NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
-
+  nsRefPtr<nsContentList> nodeList =
+    doc->GetElementsByTagName(NS_LITERAL_STRING("base"));
+
+  // If no base tag, then set baseURL to the document's URL.  This is very
+  // important, else relative URLs for links and images are wrong
+  if (!nodeList || !nodeList->Item(0)) {
     return doc->SetBaseURI(doc->GetDocumentURI());
   }
   return NS_OK;
 }
 
 /* This routine is needed to provide a bottleneck for typing for logging
    purposes.  Can't use HandleKeyPress() (above) for that since it takes
    a nsIDOMKeyEvent* parameter.  So instead we pass enough info through
@@ -1042,390 +1046,367 @@ nsHTMLEditor::TypedText(const nsAString&
     // only inserts a br node
     nsCOMPtr<nsIDOMNode> brNode;
     return InsertBR(address_of(brNode));
   }
 
   return nsPlaintextEditor::TypedText(aString, aAction);
 }
 
-NS_IMETHODIMP nsHTMLEditor::TabInTable(bool inIsShift, bool *outHandled)
+NS_IMETHODIMP
+nsHTMLEditor::TabInTable(bool inIsShift, bool* outHandled)
 {
   NS_ENSURE_TRUE(outHandled, NS_ERROR_NULL_POINTER);
   *outHandled = false;
 
-  // Find enclosing table cell from the selection (cell may be the selected element)
-  nsCOMPtr<nsIDOMElement> cellElement;
-    // can't use |NS_LITERAL_STRING| here until |GetElementOrParentByTagName| is fixed to accept readables
-  nsresult res = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr, getter_AddRefs(cellElement));
-  NS_ENSURE_SUCCESS(res, res);
+  // Find enclosing table cell from selection (cell may be selected element)
+  nsCOMPtr<Element> cellElement =
+    GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nullptr);
   // Do nothing -- we didn't find a table cell
   NS_ENSURE_TRUE(cellElement, NS_OK);
 
   // find enclosing table
-  nsCOMPtr<nsIDOMNode> tbl = GetEnclosingTable(cellElement);
-  NS_ENSURE_TRUE(tbl, res);
+  nsCOMPtr<Element> table = GetEnclosingTable(cellElement);
+  NS_ENSURE_TRUE(table, NS_OK);
 
   // advance to next cell
   // first create an iterator over the table
-  nsCOMPtr<nsIContentIterator> iter =
-      do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res);
-  NS_ENSURE_SUCCESS(res, res);
-  NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
-  nsCOMPtr<nsIContent> cTbl = do_QueryInterface(tbl);
-  nsCOMPtr<nsIContent> cBlock = do_QueryInterface(cellElement);
-  res = iter->Init(cTbl);
+  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
+  nsresult res = iter->Init(table);
   NS_ENSURE_SUCCESS(res, res);
   // position iter at block
-  res = iter->PositionAt(cBlock);
+  res = iter->PositionAt(cellElement);
   NS_ENSURE_SUCCESS(res, res);
 
-  nsCOMPtr<nsIDOMNode> node;
-  do
-  {
-    if (inIsShift)
+  nsCOMPtr<nsINode> node;
+  do {
+    if (inIsShift) {
       iter->Prev();
-    else
+    } else {
       iter->Next();
-
-    node = do_QueryInterface(iter->GetCurrentNode());
+    }
+
+    node = iter->GetCurrentNode();
 
     if (node && nsHTMLEditUtils::IsTableCell(node) &&
-        GetEnclosingTable(node) == tbl)
-    {
-      res = CollapseSelectionToDeepestNonTableFirstChild(nullptr, node);
-      NS_ENSURE_SUCCESS(res, res);
+        nsCOMPtr<Element>(GetEnclosingTable(node)) == table) {
+      CollapseSelectionToDeepestNonTableFirstChild(nullptr, node);
       *outHandled = true;
       return NS_OK;
     }
   } while (!iter->IsDone());
   
-  if (!(*outHandled) && !inIsShift)
-  {
-    // if we havent handled it yet then we must have run off the end of
-    // the table.  Insert a new row.
+  if (!(*outHandled) && !inIsShift) {
+    // If we haven't handled it yet, then we must have run off the end of the
+    // table.  Insert a new row.
     res = InsertTableRow(1, true);
     NS_ENSURE_SUCCESS(res, res);
     *outHandled = true;
-    // put selection in right place
-    // Use table code to get selection and index to new row...
-    nsCOMPtr<nsISelection>selection;
-    nsCOMPtr<nsIDOMElement> tblElement;
-    nsCOMPtr<nsIDOMElement> cell;
+    // Put selection in right place.  Use table code to get selection and index
+    // to new row...
+    nsCOMPtr<nsISelection> selection;
+    nsCOMPtr<nsIDOMElement> tblElement, cell;
     int32_t row;
     res = GetCellContext(getter_AddRefs(selection), 
                          getter_AddRefs(tblElement),
                          getter_AddRefs(cell), 
                          nullptr, nullptr,
                          &row, nullptr);
     NS_ENSURE_SUCCESS(res, res);
     // ...so that we can ask for first cell in that row...
     res = GetCellAt(tblElement, row, 0, getter_AddRefs(cell));
     NS_ENSURE_SUCCESS(res, res);
-    // ...and then set selection there.
-    // (Note that normally you should use CollapseSelectionToDeepestNonTableFirstChild(),
-    //  but we know cell is an empty new cell, so this works fine)
-    node = do_QueryInterface(cell);
-    if (node) selection->Collapse(node,0);
-    return NS_OK;
+    // ...and then set selection there.  (Note that normally you should use
+    // CollapseSelectionToDeepestNonTableFirstChild(), but we know cell is an
+    // empty new cell, so this works fine)
+    if (cell) {
+      selection->Collapse(cell, 0);
+    }
   }
   
-  return res;
+  return NS_OK;
+}
+
+already_AddRefed<Element>
+nsHTMLEditor::CreateBR(nsINode* aNode, int32_t aOffset, EDirection aSelect)
+{
+  nsCOMPtr<nsIDOMNode> parent = GetAsDOMNode(aNode);
+  int32_t offset = aOffset;
+  nsCOMPtr<nsIDOMNode> outBRNode;
+  // We assume everything is fine if the br is not null, irrespective of retval
+  CreateBRImpl(address_of(parent), &offset, address_of(outBRNode), aSelect);
+  nsCOMPtr<Element> ret = do_QueryInterface(outBRNode);
+  return ret.forget();
 }
 
 NS_IMETHODIMP nsHTMLEditor::CreateBR(nsIDOMNode *aNode, int32_t aOffset, nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect)
 {
   nsCOMPtr<nsIDOMNode> parent = aNode;
   int32_t offset = aOffset;
   return CreateBRImpl(address_of(parent), &offset, outBRNode, aSelect);
 }
 
-nsresult 
-nsHTMLEditor::CollapseSelectionToDeepestNonTableFirstChild(nsISelection *aSelection, nsIDOMNode *aNode)
+void
+nsHTMLEditor::CollapseSelectionToDeepestNonTableFirstChild(
+                                         Selection* aSelection, nsINode* aNode)
 {
-  NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
-  nsresult res;
-
-  nsCOMPtr<nsISelection> selection;
-  if (aSelection)
-  {
-    selection = aSelection;
-  } else {
-    res = GetSelection(getter_AddRefs(selection));
-    NS_ENSURE_SUCCESS(res, res);
-    NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
+  MOZ_ASSERT(aNode);
+
+  nsRefPtr<Selection> selection = aSelection;
+  if (!selection) {
+    selection = GetSelection();
+  }
+  if (!selection) {
+    // Nothing to do
+    return;
   }
-  nsCOMPtr<nsIDOMNode> node = aNode;
-  nsCOMPtr<nsIDOMNode> child;
-  
-  do {
-    node->GetFirstChild(getter_AddRefs(child));
-    
-    if (child)
-    {
-      // Stop if we find a table
-      // don't want to go into nested tables
-      if (nsHTMLEditUtils::IsTable(child)) break;
-      // hey, it'g gotta be a container too!
-      if (!IsContainer(child)) break;
-      node = child;
+
+  nsCOMPtr<nsINode> node = aNode;
+
+  for (nsCOMPtr<nsIContent> child = node->GetFirstChild();
+       child;
+       child = child->GetFirstChild()) {
+    // Stop if we find a table, don't want to go into nested tables
+    if (nsHTMLEditUtils::IsTable(child) || !IsContainer(child)) {
+      break;
     }
-  }
-  while (child);
-
-  selection->Collapse(node,0);
-  return NS_OK;
+    node = child;
+  };
+
+  selection->Collapse(node, 0);
 }
 
 
-// This is mostly like InsertHTMLWithCharsetAndContext, 
-//  but we can't use that because it is selection-based and 
-//  the rules code won't let us edit under the <head> node
+/**
+ * This is mostly like InsertHTMLWithCharsetAndContext, but we can't use that
+ * because it is selection-based and the rules code won't let us edit under the
+ * <head> node
+ */
 NS_IMETHODIMP
 nsHTMLEditor::ReplaceHeadContentsWithHTML(const nsAString& aSourceToInsert)
 {
-  nsAutoRules beginRulesSniffing(this, EditAction::ignore, nsIEditor::eNone); // don't do any post processing, rules get confused
-  nsCOMPtr<nsISelection> selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
+  // don't do any post processing, rules get confused
+  nsAutoRules beginRulesSniffing(this, EditAction::ignore, nsIEditor::eNone);
+  nsRefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   ForceCompositionEnd();
 
-  // Do not use nsAutoRules -- rules code won't let us insert in <head>
-  // Use the head node as a parent and delete/insert directly
-  nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
+  // Do not use nsAutoRules -- rules code won't let us insert in <head>.  Use
+  // the head node as a parent and delete/insert directly.
+  nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
   NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
 
-  nsCOMPtr<nsIDOMNodeList>nodeList; 
-  res = doc->GetElementsByTagName(NS_LITERAL_STRING("head"), getter_AddRefs(nodeList));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<nsContentList> nodeList =
+    doc->GetElementsByTagName(NS_LITERAL_STRING("head"));
   NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER);
 
-  uint32_t count; 
-  nodeList->GetLength(&count);
-  if (count < 1) return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIDOMNode> headNode;
-  res = nodeList->Item(0, getter_AddRefs(headNode)); 
-  NS_ENSURE_SUCCESS(res, res);
+  nsCOMPtr<nsIContent> headNode = nodeList->Item(0);
   NS_ENSURE_TRUE(headNode, NS_ERROR_NULL_POINTER);
 
-  // First, make sure there are no return chars in the source.
-  // Bad things happen if you insert returns (instead of dom newlines, \n)
-  // into an editor document.
+  // First, make sure there are no return chars in the source.  Bad things
+  // happen if you insert returns (instead of dom newlines, \n) into an editor
+  // document.
   nsAutoString inputString (aSourceToInsert);  // hope this does copy-on-write
  
   // Windows linebreaks: Map CRLF to LF:
   inputString.ReplaceSubstring(MOZ_UTF16("\r\n"),
                                MOZ_UTF16("\n"));
  
   // Mac linebreaks: Map any remaining CR to LF:
   inputString.ReplaceSubstring(MOZ_UTF16("\r"),
                                MOZ_UTF16("\n"));
 
   nsAutoEditBatch beginBatching(this);
 
-  res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
-  NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
-
   // Get the first range in the selection, for context:
-  nsCOMPtr<nsIDOMRange> range;
-  res = selection->GetRangeAt(0, getter_AddRefs(range));
-  NS_ENSURE_SUCCESS(res, res);
-
-  nsCOMPtr<nsIDOMDocumentFragment> docfrag;
-  res = range->CreateContextualFragment(inputString,
-                                        getter_AddRefs(docfrag));
-
-  //XXXX BUG 50965: This is not returning the text between <title> ... </title>
-  // Special code is needed in JS to handle title anyway, so it really doesn't matter!
-
-  if (NS_FAILED(res))
-  {
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
+  NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
+
+  ErrorResult err;
+  nsRefPtr<DocumentFragment> docfrag =
+    range->CreateContextualFragment(inputString, err);
+
+  // XXXX BUG 50965: This is not returning the text between <title>...</title>
+  // Special code is needed in JS to handle title anyway, so it doesn't matter!
+
+  if (err.Failed()) {
 #ifdef DEBUG
     printf("Couldn't create contextual fragment: error was %X\n",
-           static_cast<uint32_t>(res));
+           static_cast<uint32_t>(err.ErrorCode()));
 #endif
-    return res;
+    return err.ErrorCode();
   }
   NS_ENSURE_TRUE(docfrag, NS_ERROR_NULL_POINTER);
 
-  nsCOMPtr<nsIDOMNode> child;
-
   // First delete all children in head
-  do {
-    res = headNode->GetFirstChild(getter_AddRefs(child));
+  while (nsCOMPtr<nsIContent> child = headNode->GetFirstChild()) {
+    nsresult res = DeleteNode(child);
     NS_ENSURE_SUCCESS(res, res);
-    if (child)
-    {
-      res = DeleteNode(child);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-  } while (child);
+  }
 
   // Now insert the new nodes
   int32_t offsetOfNewNode = 0;
-  nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
 
   // Loop over the contents of the fragment and move into the document
-  do {
-    res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
+  while (nsCOMPtr<nsIContent> child = docfrag->GetFirstChild()) {
+    nsresult res = InsertNode(child, headNode, offsetOfNewNode++);
     NS_ENSURE_SUCCESS(res, res);
-    if (child)
-    {
-      res = InsertNode(child, headNode, offsetOfNewNode++);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-  } while (child);
-
-  return res;
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString)
 {
   ForceCompositionEnd();
 
-  nsCOMPtr<nsISelection>selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
-
-  nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
+  nsRefPtr<Selection> selection = GetSelection();
+  NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
+
+  nsCOMPtr<Element> bodyElement = GetRoot();
   NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
 
   // Find where the <body> tag starts.
   nsReadingIterator<char16_t> beginbody;
   nsReadingIterator<char16_t> endbody;
   aSourceString.BeginReading(beginbody);
   aSourceString.EndReading(endbody);
   bool foundbody = CaseInsensitiveFindInReadable(NS_LITERAL_STRING("<body"),
-                                                   beginbody, endbody);
+                                                 beginbody, endbody);
 
   nsReadingIterator<char16_t> beginhead;
   nsReadingIterator<char16_t> endhead;
   aSourceString.BeginReading(beginhead);
   aSourceString.EndReading(endhead);
   bool foundhead = CaseInsensitiveFindInReadable(NS_LITERAL_STRING("<head"),
-                                                   beginhead, endhead);
+                                                 beginhead, endhead);
   // a valid head appears before the body
-  if (foundbody && beginhead.get() > beginbody.get())
+  if (foundbody && beginhead.get() > beginbody.get()) {
     foundhead = false;
+  }
 
   nsReadingIterator<char16_t> beginclosehead;
   nsReadingIterator<char16_t> endclosehead;
   aSourceString.BeginReading(beginclosehead);
   aSourceString.EndReading(endclosehead);
 
   // Find the index after "<head>"
   bool foundclosehead = CaseInsensitiveFindInReadable(
            NS_LITERAL_STRING("</head>"), beginclosehead, endclosehead);
   // a valid close head appears after a found head
-  if (foundhead && beginhead.get() > beginclosehead.get())
+  if (foundhead && beginhead.get() > beginclosehead.get()) {
     foundclosehead = false;
+  }
   // a valid close head appears before a found body
-  if (foundbody && beginclosehead.get() > beginbody.get())
+  if (foundbody && beginclosehead.get() > beginbody.get()) {
     foundclosehead = false;
+  }
   
   // Time to change the document
   nsAutoEditBatch beginBatching(this);
 
   nsReadingIterator<char16_t> endtotal;
   aSourceString.EndReading(endtotal);
 
+  nsresult res;
   if (foundhead) {
-    if (foundclosehead)
+    if (foundclosehead) {
       res = ReplaceHeadContentsWithHTML(Substring(beginhead, beginclosehead));
-    else if (foundbody)
+    } else if (foundbody) {
       res = ReplaceHeadContentsWithHTML(Substring(beginhead, beginbody));
-    else
-      // XXX Without recourse to some parser/content sink/docshell hackery
-      // we don't really know where the head ends and the body begins
-      // so we assume that there is no body
+    } else {
+      // XXX Without recourse to some parser/content sink/docshell hackery we
+      // don't really know where the head ends and the body begins so we assume
+      // that there is no body
       res = ReplaceHeadContentsWithHTML(Substring(beginhead, endtotal));
+    }
   } else {
     nsReadingIterator<char16_t> begintotal;
     aSourceString.BeginReading(begintotal);
     NS_NAMED_LITERAL_STRING(head, "<head>");
-    if (foundclosehead)
-      res = ReplaceHeadContentsWithHTML(head + Substring(begintotal, beginclosehead));
-    else if (foundbody)
-      res = ReplaceHeadContentsWithHTML(head + Substring(begintotal, beginbody));
-    else
-      // XXX Without recourse to some parser/content sink/docshell hackery
-      // we don't really know where the head ends and the body begins
-      // so we assume that there is no head
+    if (foundclosehead) {
+      res = ReplaceHeadContentsWithHTML(head + Substring(begintotal,
+                                                         beginclosehead));
+    } else if (foundbody) {
+      res = ReplaceHeadContentsWithHTML(head + Substring(begintotal,
+                                                         beginbody));
+    } else {
+      // XXX Without recourse to some parser/content sink/docshell hackery we
+      // don't really know where the head ends and the body begins so we assume
+      // that there is no head
       res = ReplaceHeadContentsWithHTML(head);
+    }
   }
   NS_ENSURE_SUCCESS(res, res);
 
   res = SelectAll();
   NS_ENSURE_SUCCESS(res, res);
 
   if (!foundbody) {
     NS_NAMED_LITERAL_STRING(body, "<body>");
-    // XXX Without recourse to some parser/content sink/docshell hackery
-    // we don't really know where the head ends and the body begins
-    if (foundclosehead) // assume body starts after the head ends
+    // XXX Without recourse to some parser/content sink/docshell hackery we
+    // don't really know where the head ends and the body begins
+    if (foundclosehead) {
+      // assume body starts after the head ends
       res = LoadHTML(body + Substring(endclosehead, endtotal));
-    else if (foundhead) // assume there is no body
+    } else if (foundhead) {
+      // assume there is no body
       res = LoadHTML(body);
-    else // assume there is no head, the entire source is body
+    } else {
+      // assume there is no head, the entire source is body
       res = LoadHTML(body + aSourceString);
+    }
     NS_ENSURE_SUCCESS(res, res);
 
-    nsCOMPtr<nsIDOMElement> divElement;
-    res = CreateElementWithDefaults(NS_LITERAL_STRING("div"), getter_AddRefs(divElement));
-    NS_ENSURE_SUCCESS(res, res);
-
-    res = CloneAttributes(bodyElement, divElement);
-    NS_ENSURE_SUCCESS(res, res);
+    nsCOMPtr<Element> divElement =
+      CreateElementWithDefaults(NS_LITERAL_STRING("div"));
+    NS_ENSURE_TRUE(divElement, NS_ERROR_FAILURE);
+
+    CloneAttributes(bodyElement->AsDOMNode(), divElement->AsDOMNode());
 
     return BeginningOfDocument();
   }
 
   res = LoadHTML(Substring(beginbody, endtotal));
   NS_ENSURE_SUCCESS(res, res);
 
   // Now we must copy attributes user might have edited on the <body> tag
-  //  because InsertHTML (actually, CreateContextualFragment()) 
-  //  will never return a body node in the DOM fragment
+  // because InsertHTML (actually, CreateContextualFragment()) will never
+  // return a body node in the DOM fragment
   
   // We already know where "<body" begins
   nsReadingIterator<char16_t> beginclosebody = beginbody;
   nsReadingIterator<char16_t> endclosebody;
   aSourceString.EndReading(endclosebody);
-  if (!FindInReadable(NS_LITERAL_STRING(">"),beginclosebody,endclosebody))
+  if (!FindInReadable(NS_LITERAL_STRING(">"), beginclosebody, endclosebody)) {
     return NS_ERROR_FAILURE;
-
-  // Truncate at the end of the body tag
-  // Kludge of the year: fool the parser by replacing "body" with "div" so we get a node
+  }
+
+  // Truncate at the end of the body tag.  Kludge of the year: fool the parser
+  // by replacing "body" with "div" so we get a node
   nsAutoString bodyTag;
   bodyTag.AssignLiteral("<div ");
   bodyTag.Append(Substring(endbody, endclosebody));
 
-  nsCOMPtr<nsIDOMRange> range;
-  res = selection->GetRangeAt(0, getter_AddRefs(range));
-  NS_ENSURE_SUCCESS(res, res);
-
-  nsCOMPtr<nsIDOMDocumentFragment> docfrag;
-  res = range->CreateContextualFragment(bodyTag, getter_AddRefs(docfrag));
-  NS_ENSURE_SUCCESS(res, res);
-
-  nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
-  NS_ENSURE_TRUE(fragmentAsNode, NS_ERROR_NULL_POINTER);
-  
-  nsCOMPtr<nsIDOMNode> child;
-  res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
+  NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
+
+  ErrorResult rv;
+  nsRefPtr<DocumentFragment> docfrag =
+    range->CreateContextualFragment(bodyTag, rv);
+  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
+  NS_ENSURE_TRUE(docfrag, NS_ERROR_NULL_POINTER);
+
+  nsCOMPtr<nsIContent> child = docfrag->GetFirstChild();
   NS_ENSURE_TRUE(child, NS_ERROR_NULL_POINTER);
   
   // Copy all attributes from the div child to current body element
-  res = CloneAttributes(bodyElement, child);
+  res = CloneAttributes(bodyElement->AsDOMNode(), child->AsDOMNode());
   NS_ENSURE_SUCCESS(res, res);
   
   // place selection at first editable content
   return BeginningOfDocument();
 }
 
 void
 nsHTMLEditor::NormalizeEOLInsertPosition(nsIDOMNode *firstNodeToInsert,
@@ -2269,117 +2250,114 @@ nsHTMLEditor::Align(const nsAString& aAl
   nsresult res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   if (cancel || NS_FAILED(res))
     return res;
   
   res = mRules->DidDoAction(selection, &ruleInfo, res);
   return res;
 }
 
-NS_IMETHODIMP
-nsHTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn)
+already_AddRefed<Element>
+nsHTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName,
+                                          nsINode* aNode)
 {
-  NS_ENSURE_TRUE(!aTagName.IsEmpty(), NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(aReturn, NS_ERROR_NULL_POINTER);
-
-  nsCOMPtr<nsINode> current = do_QueryInterface(aNode);
-  if (!current) {
+  MOZ_ASSERT(!aTagName.IsEmpty());
+
+  nsCOMPtr<nsINode> node = aNode;
+  if (!node) {
     // If no node supplied, get it from anchor node of current selection
     nsRefPtr<Selection> selection = GetSelection();
-    NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
+    NS_ENSURE_TRUE(selection, nullptr);
 
     nsCOMPtr<nsINode> anchorNode = selection->GetAnchorNode();
-    NS_ENSURE_TRUE(anchorNode, NS_ERROR_FAILURE);
+    NS_ENSURE_TRUE(anchorNode, nullptr);
 
     // Try to get the actual selected node
     if (anchorNode->HasChildNodes() && anchorNode->IsContent()) {
-      uint32_t offset = selection->AnchorOffset();
-      current = anchorNode->GetChildAt(offset);
+      node = anchorNode->GetChildAt(selection->AnchorOffset());
     }
-    // anchor node is probably a text node - just use that
-    if (!current) {
-      current = anchorNode;
+    // Anchor node is probably a text node - just use that
+    if (!node) {
+      node = anchorNode;
     }
   }
 
-  nsCOMPtr<nsIDOMNode> currentNode = current->AsDOMNode();
-
-  nsAutoString TagName(aTagName);
-  ToLowerCase(TagName);
-  bool getLink = IsLinkTag(TagName);
-  bool getNamedAnchor = IsNamedAnchorTag(TagName);
-  if ( getLink || getNamedAnchor)
-  {
-    TagName.AssignLiteral("a");  
+  nsCOMPtr<Element> current;
+  if (node->IsElement()) {
+    current = node->AsElement();
+  } else if (node->GetParentElement()) {
+    current = node->GetParentElement();
+  } else {
+    // Neither aNode nor its parent is an element, so no ancestor is
+    MOZ_ASSERT(!node->GetParentNode() ||
+               !node->GetParentNode()->GetParentNode());
+    return nullptr;
+  }
+
+  nsAutoString tagName(aTagName);
+  ToLowerCase(tagName);
+  bool getLink = IsLinkTag(tagName);
+  bool getNamedAnchor = IsNamedAnchorTag(tagName);
+  if (getLink || getNamedAnchor) {
+    tagName.AssignLiteral("a");
   }
-  bool findTableCell = TagName.EqualsLiteral("td");
-  bool findList = TagName.EqualsLiteral("list");
-
-  // default is null - no element found
-  *aReturn = nullptr;
-  
-  nsCOMPtr<nsIDOMNode> parent;
-  bool bNodeFound = false;
-
-  while (true)
-  {
-    nsAutoString currentTagName; 
+  bool findTableCell = tagName.EqualsLiteral("td");
+  bool findList = tagName.EqualsLiteral("list");
+
+  for (; current; current = current->GetParentElement()) {
     // Test if we have a link (an anchor with href set)
-    if ( (getLink && nsHTMLEditUtils::IsLink(currentNode)) ||
-         (getNamedAnchor && nsHTMLEditUtils::IsNamedAnchor(currentNode)) )
-    {
-      bNodeFound = true;
+    if ((getLink && nsHTMLEditUtils::IsLink(current)) ||
+        (getNamedAnchor && nsHTMLEditUtils::IsNamedAnchor(current))) {
+      return current.forget();
+    }
+    if (findList) {
+      // Match "ol", "ul", or "dl" for lists
+      if (nsHTMLEditUtils::IsList(current)) {
+        return current.forget();
+      }
+    } else if (findTableCell) {
+      // Table cells are another special case: match either "td" or "th"
+      if (nsHTMLEditUtils::IsTableCell(current)) {
+        return current.forget();
+      }
+    } else if (current->NodeName().Equals(tagName,
+                   nsCaseInsensitiveStringComparator())) {
+      return current.forget();
+    }
+
+    // Stop searching if parent is a body tag.  Note: Originally used IsRoot to
+    // stop at table cells, but that's too messy when you are trying to find
+    // the parent table
+    if (current->GetParentElement() &&
+        current->GetParentElement()->Tag() == nsGkAtoms::body) {
       break;
-    } else {
-      if (findList)
-      {
-        // Match "ol", "ul", or "dl" for lists
-        if (nsHTMLEditUtils::IsList(currentNode))
-          goto NODE_FOUND;
-
-      } else if (findTableCell)
-      {
-        // Table cells are another special case:
-        // Match either "td" or "th" for them
-        if (nsHTMLEditUtils::IsTableCell(currentNode))
-          goto NODE_FOUND;
-
-      } else {
-        currentNode->GetNodeName(currentTagName);
-        if (currentTagName.Equals(TagName, nsCaseInsensitiveStringComparator()))
-        {
-NODE_FOUND:
-          bNodeFound = true;
-          break;
-        } 
-      }
     }
-    // Search up the parent chain
-    // We should never fail because of root test below, but lets be safe
-    // XXX: ERROR_HANDLING error return code lost
-    if (NS_FAILED(currentNode->GetParentNode(getter_AddRefs(parent))) || !parent)
-      break;
-
-    // Stop searching if parent is a body tag
-    nsAutoString parentTagName;
-    parent->GetNodeName(parentTagName);
-    // Note: Originally used IsRoot to stop at table cells,
-    //  but that's too messy when you are trying to find the parent table
-    if(parentTagName.LowerCaseEqualsLiteral("body"))
-      break;
-
-    currentNode = parent;
   }
 
-  if (!bNodeFound) {
+  return nullptr;
+}
+
+NS_IMETHODIMP
+nsHTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName,
+                                          nsIDOMNode* aNode,
+                                          nsIDOMElement** aReturn)
+{
+  NS_ENSURE_TRUE(!aTagName.IsEmpty(), NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aReturn, NS_ERROR_NULL_POINTER);
+
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  nsCOMPtr<Element> parent =
+    GetElementOrParentByTagName(aTagName, node);
+  nsCOMPtr<nsIDOMElement> ret = do_QueryInterface(parent);
+
+  if (!ret) {
     return NS_EDITOR_ELEMENT_NOT_FOUND;
   }
 
-  nsCOMPtr<nsIDOMElement> currentElement = do_QueryInterface(currentNode);
-  currentElement.forget(aReturn);
+  ret.forget(aReturn);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::GetSelectedElement(const nsAString& aTagName, nsIDOMElement** aReturn)
 {
   NS_ENSURE_TRUE(aReturn , NS_ERROR_NULL_POINTER);
   
@@ -2578,75 +2556,77 @@ nsHTMLEditor::GetSelectedElement(const n
       NS_ADDREF(*aReturn);
     }
   } 
   else res = NS_EDITOR_ELEMENT_NOT_FOUND;
 
   return res;
 }
 
+already_AddRefed<Element>
+nsHTMLEditor::CreateElementWithDefaults(const nsAString& aTagName)
+{
+  MOZ_ASSERT(!aTagName.IsEmpty());
+
+  nsAutoString tagName(aTagName);
+  ToLowerCase(tagName);
+  nsAutoString realTagName;
+
+  if (IsLinkTag(tagName) || IsNamedAnchorTag(tagName)) {
+    realTagName.AssignLiteral("a");
+  } else {
+    realTagName = tagName;
+  }
+  // We don't use editor's CreateElement because we don't want to go through
+  // the transaction system
+
+  // New call to use instead to get proper HTML element, bug 39919
+  ErrorResult rv;
+  nsCOMPtr<dom::Element> newElement = CreateHTMLContent(realTagName, rv);
+  if (rv.Failed() || !newElement) {
+    return nullptr;
+  }
+
+  // Mark the new element dirty, so it will be formatted
+  newElement->SetAttribute(NS_LITERAL_STRING("_moz_dirty"), EmptyString(), rv);
+
+  // Set default values for new elements
+  if (tagName.EqualsLiteral("table")) {
+    newElement->SetAttribute(NS_LITERAL_STRING("cellpadding"),
+                             NS_LITERAL_STRING("2"), rv);
+    NS_ENSURE_SUCCESS(rv.ErrorCode(), nullptr);
+    newElement->SetAttribute(NS_LITERAL_STRING("cellspacing"),
+                             NS_LITERAL_STRING("2"), rv);
+    NS_ENSURE_SUCCESS(rv.ErrorCode(), nullptr);
+    newElement->SetAttribute(NS_LITERAL_STRING("border"),
+                             NS_LITERAL_STRING("1"), rv);
+    NS_ENSURE_SUCCESS(rv.ErrorCode(), nullptr);
+  } else if (tagName.EqualsLiteral("td")) {
+    nsresult res = SetAttributeOrEquivalent(
+        static_cast<nsIDOMElement*>(newElement->AsDOMNode()),
+        NS_LITERAL_STRING("valign"), NS_LITERAL_STRING("top"), true);
+    NS_ENSURE_SUCCESS(res, nullptr);
+  }
+  // ADD OTHER TAGS HERE
+
+  return newElement.forget();
+}
+
 NS_IMETHODIMP
 nsHTMLEditor::CreateElementWithDefaults(const nsAString& aTagName, nsIDOMElement** aReturn)
 {
-  nsresult res=NS_ERROR_NOT_INITIALIZED;
-  if (aReturn)
-    *aReturn = nullptr;
-
-//  NS_ENSURE_TRUE(aTagName && aReturn, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(!aTagName.IsEmpty() && aReturn, NS_ERROR_NULL_POINTER);
-    
-  nsAutoString TagName(aTagName);
-  ToLowerCase(TagName);
-  nsAutoString realTagName;
-
-  if (IsLinkTag(TagName) || IsNamedAnchorTag(TagName))
-  {
-    realTagName.AssignLiteral("a");
-  } else {
-    realTagName = TagName;
-  }
-  //We don't use editor's CreateElement because we don't want to 
-  //  go through the transaction system
-
-  nsCOMPtr<nsIDOMElement>newElement;
-  nsCOMPtr<dom::Element> newContent;
-  nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
-  NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
-
-  //new call to use instead to get proper HTML element, bug# 39919
-  res = CreateHTMLContent(realTagName, getter_AddRefs(newContent));
-  newElement = do_QueryInterface(newContent);
-  if (NS_FAILED(res) || !newElement)
-    return NS_ERROR_FAILURE;
-
-  // Mark the new element dirty, so it will be formatted
-  newElement->SetAttribute(NS_LITERAL_STRING("_moz_dirty"), EmptyString());
-
-  // Set default values for new elements
-  if (TagName.EqualsLiteral("table")) {
-    res = newElement->SetAttribute(NS_LITERAL_STRING("cellpadding"),NS_LITERAL_STRING("2"));
-    NS_ENSURE_SUCCESS(res, res);
-    res = newElement->SetAttribute(NS_LITERAL_STRING("cellspacing"),NS_LITERAL_STRING("2"));
-    NS_ENSURE_SUCCESS(res, res);
-    res = newElement->SetAttribute(NS_LITERAL_STRING("border"),NS_LITERAL_STRING("1"));
-  } else if (TagName.EqualsLiteral("td"))
-  {
-    res = SetAttributeOrEquivalent(newElement, NS_LITERAL_STRING("valign"),
-                                   NS_LITERAL_STRING("top"), true);
-  }
-  // ADD OTHER TAGS HERE
-
-  if (NS_SUCCEEDED(res))
-  {
-    *aReturn = newElement;
-    // Getters must addref
-    NS_ADDREF(*aReturn);
-  }
-
-  return res;
+  *aReturn = nullptr;
+
+  nsCOMPtr<Element> newElement = CreateElementWithDefaults(aTagName);
+  nsCOMPtr<nsIDOMElement> ret = do_QueryInterface(newElement);
+  NS_ENSURE_TRUE(ret, NS_ERROR_FAILURE);
+
+  ret.forget(aReturn);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement)
 {
   NS_ENSURE_TRUE(aAnchorElement, NS_ERROR_NULL_POINTER);
 
   // We must have a real selection
@@ -3520,39 +3500,41 @@ nsHTMLEditor::TagCanContainTag(nsIAtom* 
     childTagEnum = parserService->HTMLAtomTagToId(aChildTag);
   }
 
   int32_t parentTagEnum = parserService->HTMLAtomTagToId(aParentTag);
   return nsHTMLEditUtils::CanContain(parentTagEnum, childTagEnum);
 }
 
 bool
-nsHTMLEditor::IsContainer(nsIDOMNode *aNode)
-{
-  if (!aNode) {
-    return false;
-  }
-
-  nsAutoString stringTag;
-
-  nsresult rv = aNode->GetNodeName(stringTag);
-  NS_ENSURE_SUCCESS(rv, false);
+nsHTMLEditor::IsContainer(nsINode* aNode) {
+  MOZ_ASSERT(aNode);
 
   int32_t tagEnum;
   // XXX Should this handle #cdata-section too?
-  if (stringTag.EqualsLiteral("#text")) {
+  if (aNode->IsNodeOfType(nsINode::eTEXT)) {
     tagEnum = eHTMLTag_text;
-  }
-  else {
-    tagEnum = nsContentUtils::GetParserService()->HTMLStringTagToId(stringTag);
+  } else {
+    tagEnum =
+      nsContentUtils::GetParserService()->HTMLStringTagToId(aNode->NodeName());
   }
 
   return nsHTMLEditUtils::IsContainer(tagEnum);
 }
 
+bool
+nsHTMLEditor::IsContainer(nsIDOMNode *aNode)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  if (!node) {
+    return false;
+  }
+  return IsContainer(node);
+}
+
 
 NS_IMETHODIMP 
 nsHTMLEditor::SelectEntireDocument(nsISelection *aSelection)
 {
   if (!aSelection || !mRules) { return NS_ERROR_NULL_POINTER; }
   
   // Protect the edit rules object from dying
   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
@@ -3730,31 +3712,41 @@ nsHTMLEditor::SetCaretInTableCell(nsIDOM
   NS_ENSURE_SUCCESS(rv, false);
   NS_ENSURE_TRUE(selection, false);
 
   return NS_SUCCEEDED(selection->CollapseNative(node, 0));
 }            
 
 ///////////////////////////////////////////////////////////////////////////
 // GetEnclosingTable: find ancestor who is a table, if any
-//                  
-nsCOMPtr<nsIDOMNode> 
+//
+already_AddRefed<Element>
+nsHTMLEditor::GetEnclosingTable(nsINode* aNode)
+{
+  MOZ_ASSERT(aNode);
+
+  for (nsCOMPtr<Element> block = GetBlockNodeParent(aNode);
+       block;
+       block = GetBlockNodeParent(block)) {
+    if (nsHTMLEditUtils::IsTable(block)) {
+      return block.forget();
+    }
+  }
+  return nullptr;
+}
+
+nsCOMPtr<nsIDOMNode>
 nsHTMLEditor::GetEnclosingTable(nsIDOMNode *aNode)
 {
   NS_PRECONDITION(aNode, "null node passed to nsHTMLEditor::GetEnclosingTable");
-  nsCOMPtr<nsIDOMNode> tbl, tmp, node = aNode;
-
-  while (!tbl)
-  {
-    tmp = GetBlockNodeParent(node);
-    if (!tmp) break;
-    if (nsHTMLEditUtils::IsTable(tmp)) tbl = tmp;
-    node = tmp;
-  }
-  return tbl;
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  NS_ENSURE_TRUE(node, nullptr);
+  nsCOMPtr<Element> table = GetEnclosingTable(node);
+  nsCOMPtr<nsIDOMNode> ret = do_QueryInterface(table);
+  return ret;
 }
 
 
 /* this method scans the selection for adjacent text nodes
  * and collapses them into a single text node.
  * "adjacent" means literally adjacent siblings of the same parent.
  * Uses nsEditor::JoinNodes so action is undoable. 
  * Should be called within the context of a batch transaction.
@@ -4700,18 +4692,17 @@ nsHTMLEditor::SetCSSBackgroundColor(cons
       res = range->GetEndOffset(&endOffset);
       NS_ENSURE_SUCCESS(res, res);
       if ((startNode == endNode) && IsTextNode(startNode))
       {
         // let's find the block container of the text node
         nsCOMPtr<nsIDOMNode> blockParent;
         blockParent = GetBlockNodeParent(startNode);
         // and apply the background color to that block container
-        if (cachedBlockParent != blockParent)
-        {
+        if (blockParent && cachedBlockParent != blockParent) {
           cachedBlockParent = blockParent;
           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
           int32_t count;
           res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
           NS_ENSURE_SUCCESS(res, res);
         }
       }
       else if ((startNode == endNode) && nsTextEditUtils::IsBody(startNode) && isCollapsed)
@@ -4729,18 +4720,17 @@ nsHTMLEditor::SetCSSBackgroundColor(cons
         nsCOMPtr<nsIDOMNode> selectedNode = GetChildAt(startNode, startOffset);
         bool isBlock =false;
         res = NodeIsBlockStatic(selectedNode, &isBlock);
         NS_ENSURE_SUCCESS(res, res);
         nsCOMPtr<nsIDOMNode> blockParent = selectedNode;
         if (!isBlock) {
           blockParent = GetBlockNodeParent(selectedNode);
         }
-        if (cachedBlockParent != blockParent)
-        {
+        if (blockParent && cachedBlockParent != blockParent) {
           cachedBlockParent = blockParent;
           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
           int32_t count;
           res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
           NS_ENSURE_SUCCESS(res, res);
         }
       }
       else
@@ -4787,18 +4777,17 @@ nsHTMLEditor::SetCSSBackgroundColor(cons
         }
         // first check the start parent of the range to see if it needs to 
         // be separately handled (it does if it's a text node, due to how the
         // subtree iterator works - it will not have reported it).
         if (IsTextNode(startNode) && IsEditable(startNode))
         {
           nsCOMPtr<nsIDOMNode> blockParent;
           blockParent = GetBlockNodeParent(startNode);
-          if (cachedBlockParent != blockParent)
-          {
+          if (blockParent && cachedBlockParent != blockParent) {
             cachedBlockParent = blockParent;
             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
             int32_t count;
             res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
             NS_ENSURE_SUCCESS(res, res);
           }
         }
         
@@ -4812,18 +4801,17 @@ nsHTMLEditor::SetCSSBackgroundColor(cons
           bool isBlock =false;
           res = NodeIsBlockStatic(node, &isBlock);
           NS_ENSURE_SUCCESS(res, res);
           nsCOMPtr<nsIDOMNode> blockParent = node;
           if (!isBlock) {
             // no we don't, let's find the block ancestor
             blockParent = GetBlockNodeParent(node);
           }
-          if (cachedBlockParent != blockParent)
-          {
+          if (blockParent && cachedBlockParent != blockParent) {
             cachedBlockParent = blockParent;
             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
             int32_t count;
             // and set the property on it
             res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
             NS_ENSURE_SUCCESS(res, res);
           }
         }
@@ -4831,18 +4819,17 @@ nsHTMLEditor::SetCSSBackgroundColor(cons
         
         // last check the end parent of the range to see if it needs to 
         // be separately handled (it does if it's a text node, due to how the
         // subtree iterator works - it will not have reported it).
         if (IsTextNode(endNode) && IsEditable(endNode))
         {
           nsCOMPtr<nsIDOMNode> blockParent;
           blockParent = GetBlockNodeParent(endNode);
-          if (cachedBlockParent != blockParent)
-          {
+          if (blockParent && cachedBlockParent != blockParent) {
             cachedBlockParent = blockParent;
             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
             int32_t count;
             res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nullptr, &bgcolor, &aColor, &count, false);
             NS_ENSURE_SUCCESS(res, res);
           }
         }
       }
@@ -5447,17 +5434,17 @@ nsHTMLEditor::GetPreferredIMEState(IMESt
 already_AddRefed<nsIContent>
 nsHTMLEditor::GetInputEventTargetContent()
 {
   nsCOMPtr<nsIContent> target = GetActiveEditingHost();
   return target.forget();
 }
 
 bool
-nsHTMLEditor::IsEditable(nsIContent* aNode) {
+nsHTMLEditor::IsEditable(nsINode* aNode) {
   if (!nsPlaintextEditor::IsEditable(aNode)) {
     return false;
   }
   if (aNode->IsElement()) {
     // If we're dealing with an element, then ask it whether it's editable.
     return aNode->IsEditable();
   }
   // We might be dealing with a text node for example, which we always consider
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -106,17 +106,17 @@ public:
   virtual already_AddRefed<nsIContent> GetFocusedContent();
   virtual already_AddRefed<nsIContent> GetFocusedContentForIME();
   virtual bool IsActiveInDOMWindow();
   virtual already_AddRefed<mozilla::dom::EventTarget> GetDOMEventTarget();
   virtual mozilla::dom::Element* GetEditorRoot() MOZ_OVERRIDE;
   virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode *aNode);
   virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent);
   virtual already_AddRefed<nsIContent> GetInputEventTargetContent();
-  virtual bool IsEditable(nsIContent *aNode);
+  virtual bool IsEditable(nsINode* aNode) MOZ_OVERRIDE;
   using nsEditor::IsEditable;
 
   /* ------------ nsStubMutationObserver overrides --------- */
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   /* ------------ nsIEditorIMESupport overrides ------------ */
@@ -224,16 +224,17 @@ public:
     
   /* miscellaneous */
   // This sets background on the appropriate container element (table, cell,)
   //   or calls into nsTextEditor to set the page background
   NS_IMETHOD SetCSSBackgroundColor(const nsAString& aColor);
   NS_IMETHOD SetHTMLBackgroundColor(const nsAString& aColor);
 
   /* ------------ Block methods moved from nsEditor -------------- */
+  static already_AddRefed<mozilla::dom::Element> GetBlockNodeParent(nsINode* aNode);
   static already_AddRefed<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode);
 
   void IsNextCharInNodeWhitespace(nsIContent* aContent,
                                   int32_t aOffset,
                                   bool* outIsSpace,
                                   bool* outIsNBSP,
                                   nsIContent** outNode = nullptr,
                                   int32_t* outOffset = 0);
@@ -281,17 +282,18 @@ public:
   /** All editor operations which alter the doc should be followed
    *  with a call to EndOperation */
   NS_IMETHOD EndOperation();
 
   /** returns true if aParentTag can contain a child of type aChildTag */
   virtual bool TagCanContainTag(nsIAtom* aParentTag, nsIAtom* aChildTag);
   
   /** returns true if aNode is a container */
-  virtual bool IsContainer(nsIDOMNode *aNode);
+  virtual bool IsContainer(nsINode* aNode) MOZ_OVERRIDE;
+  virtual bool IsContainer(nsIDOMNode* aNode) MOZ_OVERRIDE;
 
   /** make the given selection span the entire document */
   NS_IMETHOD SelectEntireDocument(nsISelection *aSelection);
 
   NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement * aElement,
                                       const nsAString & aAttribute,
                                       const nsAString & aValue,
                                       bool aSuppressTransaction);
@@ -337,17 +339,18 @@ public:
                               bool aNoEmptyNodes);
 
   // Use this to assure that selection is set after attribute nodes when 
   //  trying to collapse selection at begining of a block node
   //  e.g., when setting at beginning of a table cell
   // This will stop at a table, however, since we don't want to
   //  "drill down" into nested tables.
   // aSelection is optional -- if null, we get current seletion
-  nsresult CollapseSelectionToDeepestNonTableFirstChild(nsISelection *aSelection, nsIDOMNode *aNode);
+  void CollapseSelectionToDeepestNonTableFirstChild(
+                          mozilla::dom::Selection* aSelection, nsINode* aNode);
 
   /**
    * aNode must be a non-null text node.
    * outIsEmptyNode must be non-null.
    */
   nsresult IsVisTextNode(nsIContent* aNode,
                          bool* outIsEmptyNode,
                          bool aSafeToAskFrames);
@@ -412,16 +415,18 @@ protected:
   //            Otherwise, returns null.
   already_AddRefed<nsINode> GetFocusedNode();
 
   // Return TRUE if aElement is a table-related elemet and caret was set
   bool SetCaretInTableCell(nsIDOMElement* aElement);
 
   // key event helpers
   NS_IMETHOD TabInTable(bool inIsShift, bool *outHandled);
+  already_AddRefed<mozilla::dom::Element> CreateBR(nsINode* aNode,
+      int32_t aOffset, EDirection aSelect = eNone);
   NS_IMETHOD CreateBR(nsIDOMNode *aNode, int32_t aOffset, 
                       nsCOMPtr<nsIDOMNode> *outBRNode, nsIEditor::EDirection aSelect = nsIEditor::eNone);
 
 // Table Editing (implemented in nsTableEditor.cpp)
 
   // Table utilities
 
   // Insert a new cell after or before supplied aCell. 
@@ -480,16 +485,18 @@ protected:
   NS_IMETHOD FixBadColSpan(nsIDOMElement *aTable, int32_t aColIndex, int32_t& aNewColCount);
 
   // Fallback method: Call this after using ClearSelection() and you
   //  failed to set selection to some other content in the document
   NS_IMETHOD SetSelectionAtDocumentStart(nsISelection *aSelection);
 
 // End of Table Editing utilities
   
+  static already_AddRefed<mozilla::dom::Element>
+    GetEnclosingTable(nsINode* aNode);
   static nsCOMPtr<nsIDOMNode> GetEnclosingTable(nsIDOMNode *aNode);
 
   /** content-based query returns true if <aProperty aAttribute=aValue> effects aNode
     * If <aProperty aAttribute=aValue> contains aNode, 
     * but <aProperty aAttribute=SomeOtherValue> also contains aNode and the second is
     * more deeply nested than the first, then the first does not effect aNode.
     *
     * @param aNode      The target of the query
@@ -603,16 +610,17 @@ protected:
                                         nsCOMPtr<nsIDOMNode> *outReplaceNode);
   nsresult ReplaceOrphanedStructure( bool aEnd,
                                      nsCOMArray<nsIDOMNode>& aNodeArray,
                                      nsCOMArray<nsIDOMNode>& aListAndTableArray,
                                      int32_t aHighWaterMark);
   nsIDOMNode* GetArrayEndpoint(bool aEnd, nsCOMArray<nsIDOMNode>& aNodeArray);
 
   /* small utility routine to test if a break node is visible to user */
+  bool     IsVisBreak(nsINode* aNode);
   bool     IsVisBreak(nsIDOMNode *aNode);
 
   /* utility routine to possibly adjust the insertion position when 
      inserting a block level element */
   void NormalizeEOLInsertPosition(nsIDOMNode *firstNodeToInsert,
                                   nsCOMPtr<nsIDOMNode> *insertParentNode,
                                   int32_t *insertOffset);
 
@@ -951,11 +959,15 @@ private:
   nsresult SetInlinePropertyOnNodeImpl(nsIContent* aNode,
                                        nsIAtom* aProperty,
                                        const nsAString* aAttribute,
                                        const nsAString* aValue);
   typedef enum { eInserted, eAppended } InsertedOrAppended;
   void DoContentInserted(nsIDocument* aDocument, nsIContent* aContainer,
                          nsIContent* aChild, int32_t aIndexInContainer,
                          InsertedOrAppended aInsertedOrAppended);
+  already_AddRefed<mozilla::dom::Element> GetElementOrParentByTagName(
+      const nsAString& aTagName, nsINode* aNode);
+  already_AddRefed<mozilla::dom::Element> CreateElementWithDefaults(
+      const nsAString& aTagName);
 };
 #endif //nsHTMLEditor_h__
 
--- a/editor/libeditor/html/nsHTMLEditorStyle.cpp
+++ b/editor/libeditor/html/nsHTMLEditorStyle.cpp
@@ -307,21 +307,20 @@ nsHTMLEditor::IsSimpleModifiableNode(nsI
       !element->HasAttr(kNameSpaceID_None, nsGkAtoms::style)) {
     return false;
   }
 
   // Some CSS styles are not so simple.  For instance, underline is
   // "text-decoration: underline", which decomposes into four different text-*
   // properties.  So for now, we just create a span, add the desired style, and
   // see if it matches.
-  nsCOMPtr<dom::Element> newSpan;
-  nsresult res = CreateHTMLContent(NS_LITERAL_STRING("span"),
-                                   getter_AddRefs(newSpan));
-  NS_ASSERTION(NS_SUCCEEDED(res), "CreateHTMLContent failed");
-  NS_ENSURE_SUCCESS(res, false);
+  ErrorResult rv;
+  nsCOMPtr<Element> newSpan = CreateHTMLContent(NS_LITERAL_STRING("span"), rv);
+  NS_ASSERTION(!rv.Failed(), "CreateHTMLContent failed");
+  NS_ENSURE_SUCCESS(rv.ErrorCode(), false);
   mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(newSpan, aProperty,
                                              aAttribute, aValue,
                                              /*suppress transaction*/ true);
 
   return mHTMLCSSUtils->ElementsSameStyle(newSpan, element);
 }
 
 
--- a/editor/libeditor/html/nsTableEditor.cpp
+++ b/editor/libeditor/html/nsTableEditor.cpp
@@ -3081,19 +3081,18 @@ nsHTMLEditor::GetFirstSelectedCellInTabl
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::SetSelectionAfterTableEdit(nsIDOMElement* aTable, int32_t aRow, int32_t aCol, 
                                      int32_t aDirection, bool aSelected)
 {
   NS_ENSURE_TRUE(aTable, NS_ERROR_NOT_INITIALIZED);
 
-  nsCOMPtr<nsISelection>selection;
-  nsresult res = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(res, res);
+  nsRefPtr<Selection> selection = GetSelection();
+  nsresult res;
   
   if (!selection)
   {
 #ifdef DEBUG_cmanske
     printf("Selection not found after table manipulation!\n");
 #endif
     return NS_ERROR_FAILURE;
   }
@@ -3112,17 +3111,21 @@ nsHTMLEditor::SetSelectionAfterTableEdit
           return SelectElement(cell);
         }
         else
         {
           // Set the caret to deepest first child
           //   but don't go into nested tables
           // TODO: Should we really be placing the caret at the END
           //  of the cell content?
-          return CollapseSelectionToDeepestNonTableFirstChild(selection, cell);
+          nsCOMPtr<nsINode> cellNode = do_QueryInterface(cell);
+          if (cellNode) {
+            CollapseSelectionToDeepestNonTableFirstChild(selection, cellNode);
+          }
+          return NS_OK;
         }
       } else {
         // Setup index to find another cell in the 
         //   direction requested, but move in
         //   other direction if already at beginning of row or column
         switch (aDirection)
         {
           case ePreviousColumn:
--- a/editor/libeditor/html/nsWSRunObject.cpp
+++ b/editor/libeditor/html/nsWSRunObject.cpp
@@ -20,28 +20,55 @@
 #include "nsISupportsImpl.h"
 #include "nsRange.h"
 #include "nsSelectionState.h"
 #include "nsString.h"
 #include "nsTextEditUtils.h"
 #include "nsTextFragment.h"
 #include "nsWSRunObject.h"
 
+using namespace mozilla;
+using namespace mozilla::dom;
+
 const char16_t nbsp = 160;
 
-static bool IsBlockNode(nsIDOMNode* node)
+static bool IsBlockNode(nsINode* node)
 {
-  bool isBlock (false);
-  nsHTMLEditor::NodeIsBlockStatic(node, &isBlock);
-  return isBlock;
+  return node && node->IsElement() &&
+         nsHTMLEditor::NodeIsBlockStatic(node->AsElement());
 }
 
 //- constructor / destructor -----------------------------------------------
+nsWSRunObject::nsWSRunObject(nsHTMLEditor* aEd, nsINode* aNode, int32_t aOffset)
+  : mNode(aNode)
+  , mOffset(aOffset)
+  , mPRE(false)
+  , mStartNode()
+  , mStartOffset(0)
+  , mStartReason()
+  , mStartReasonNode()
+  , mEndNode()
+  , mEndOffset(0)
+  , mEndReason()
+  , mEndReasonNode()
+  , mFirstNBSPNode()
+  , mFirstNBSPOffset(0)
+  , mLastNBSPNode()
+  , mLastNBSPOffset(0)
+  , mNodeArray()
+  , mStartRun(nullptr)
+  , mEndRun(nullptr)
+  , mHTMLEditor(aEd)
+{
+  GetWSNodes();
+  GetRuns();
+}
+
 nsWSRunObject::nsWSRunObject(nsHTMLEditor *aEd, nsIDOMNode *aNode, int32_t aOffset) :
-mNode(aNode)
+mNode(do_QueryInterface(aNode))
 ,mOffset(aOffset)
 ,mPRE(false)
 ,mStartNode()
 ,mStartOffset(0)
 ,mStartReason()
 ,mStartReasonNode()
 ,mEndNode()
 ,mEndOffset(0)
@@ -67,74 +94,104 @@ nsWSRunObject::~nsWSRunObject()
 
 
 
 //--------------------------------------------------------------------------------------------
 //   public static methods
 //--------------------------------------------------------------------------------------------
 
 nsresult
-nsWSRunObject::ScrubBlockBoundary(nsHTMLEditor *aHTMLEd, 
-                                  nsCOMPtr<nsIDOMNode> *aBlock,
+nsWSRunObject::ScrubBlockBoundary(nsHTMLEditor* aHTMLEd,
                                   BlockBoundary aBoundary,
-                                  int32_t *aOffset)
+                                  nsINode* aBlock,
+                                  int32_t aOffset)
 {
-  NS_ENSURE_TRUE(aBlock && aHTMLEd, NS_ERROR_NULL_POINTER);
-  if ((aBoundary == kBlockStart) || (aBoundary == kBlockEnd))
-    return ScrubBlockBoundaryInner(aHTMLEd, aBlock, aBoundary);
+  NS_ENSURE_TRUE(aHTMLEd && aBlock, NS_ERROR_NULL_POINTER);
+
+  int32_t offset;
+  if (aBoundary == kBlockStart) {
+    offset = 0;
+  } else if (aBoundary == kBlockEnd) {
+    offset = aBlock->Length();
+  } else {
+    // Else we are scrubbing an outer boundary - just before or after a block
+    // element.
+    NS_ENSURE_STATE(aOffset >= 0);
+    offset = aOffset;
+  }
   
-  // else we are scrubbing an outer boundary - just before or after
-  // a block element.
-  NS_ENSURE_TRUE(aOffset, NS_ERROR_NULL_POINTER);
-  nsAutoTrackDOMPoint tracker(aHTMLEd->mRangeUpdater, aBlock, aOffset);
-  nsWSRunObject theWSObj(aHTMLEd, *aBlock, *aOffset);
+  nsWSRunObject theWSObj(aHTMLEd, aBlock, offset);
   return theWSObj.Scrub();
 }
 
 nsresult 
 nsWSRunObject::PrepareToJoinBlocks(nsHTMLEditor *aHTMLEd, 
                                    nsIDOMNode *aLeftParent, 
                                    nsIDOMNode *aRightParent)
 {
-  NS_ENSURE_TRUE(aLeftParent && aRightParent && aHTMLEd, NS_ERROR_NULL_POINTER);
-  uint32_t count;
-  aHTMLEd->GetLengthOfDOMNode(aLeftParent, count);
-  nsWSRunObject leftWSObj(aHTMLEd, aLeftParent, count);
-  nsWSRunObject rightWSObj(aHTMLEd, aRightParent, 0);
+  nsCOMPtr<nsINode> leftParent(do_QueryInterface(aLeftParent));
+  nsCOMPtr<nsINode> rightParent(do_QueryInterface(aRightParent));
+  NS_ENSURE_TRUE(leftParent && rightParent && aHTMLEd, NS_ERROR_NULL_POINTER);
+
+  nsWSRunObject leftWSObj(aHTMLEd, leftParent, leftParent->Length());
+  nsWSRunObject rightWSObj(aHTMLEd, rightParent, 0);
 
   return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
 }
 
+nsresult
+nsWSRunObject::PrepareToDeleteRange(nsHTMLEditor* aHTMLEd,
+                                    nsCOMPtr<nsINode>* aStartNode,
+                                    int32_t* aStartOffset,
+                                    nsCOMPtr<nsINode>* aEndNode,
+                                    int32_t* aEndOffset)
+{
+  nsCOMPtr<nsIDOMNode> startNode(GetAsDOMNode(*aStartNode));
+  nsCOMPtr<nsIDOMNode> endNode(GetAsDOMNode(*aEndNode));
+  nsresult res =
+    PrepareToDeleteRange(aHTMLEd, address_of(startNode), aStartOffset,
+                         address_of(endNode), aEndOffset);
+  *aStartNode = do_QueryInterface(startNode);
+  *aEndNode = do_QueryInterface(endNode);
+  return res;
+}
+
 nsresult 
 nsWSRunObject::PrepareToDeleteRange(nsHTMLEditor *aHTMLEd, 
                                     nsCOMPtr<nsIDOMNode> *aStartNode,
                                     int32_t *aStartOffset, 
                                     nsCOMPtr<nsIDOMNode> *aEndNode,
                                     int32_t *aEndOffset)
 {
-  NS_ENSURE_TRUE(aStartNode && aEndNode && *aStartNode && *aEndNode && aStartOffset && aEndOffset && aHTMLEd, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aStartNode && aEndNode && aStartOffset && aEndOffset &&
+                 aHTMLEd, NS_ERROR_NULL_POINTER);
+  nsCOMPtr<nsINode> startNode(do_QueryInterface(*aStartNode));
+  nsCOMPtr<nsINode> endNode(do_QueryInterface(*aEndNode));
+  NS_ENSURE_TRUE(startNode && endNode, NS_ERROR_NULL_POINTER);
 
   nsAutoTrackDOMPoint trackerStart(aHTMLEd->mRangeUpdater, aStartNode, aStartOffset);
   nsAutoTrackDOMPoint trackerEnd(aHTMLEd->mRangeUpdater, aEndNode, aEndOffset);
   
-  nsWSRunObject leftWSObj(aHTMLEd, *aStartNode, *aStartOffset);
-  nsWSRunObject rightWSObj(aHTMLEd, *aEndNode, *aEndOffset);
+  nsWSRunObject leftWSObj(aHTMLEd, startNode, *aStartOffset);
+  nsWSRunObject rightWSObj(aHTMLEd, endNode, *aEndOffset);
 
   return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
 }
 
 nsresult 
 nsWSRunObject::PrepareToDeleteNode(nsHTMLEditor *aHTMLEd, 
                                    nsIDOMNode *aNode)
 {
-  NS_ENSURE_TRUE(aNode && aHTMLEd, NS_ERROR_NULL_POINTER);
+  nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
+  NS_ENSURE_TRUE(node && aHTMLEd, NS_ERROR_NULL_POINTER);
   
-  int32_t offset;
-  nsCOMPtr<nsIDOMNode> parent = aHTMLEd->GetNodeLocation(aNode, &offset);
-  
+  nsCOMPtr<nsINode> parent = node->GetParentNode();
+  NS_ENSURE_STATE(parent);
+  int32_t offset = parent->IndexOf(node);
+
   nsWSRunObject leftWSObj(aHTMLEd, parent, offset);
   nsWSRunObject rightWSObj(aHTMLEd, parent, offset+1);
 
   return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
 }
 
 nsresult 
 nsWSRunObject::PrepareToSplitAcrossBlocks(nsHTMLEditor *aHTMLEd, 
@@ -149,82 +206,81 @@ nsWSRunObject::PrepareToSplitAcrossBlock
 
   return wsObj.PrepareToSplitAcrossBlocksPriv();
 }
 
 //--------------------------------------------------------------------------------------------
 //   public instance methods
 //--------------------------------------------------------------------------------------------
 
-nsresult 
-nsWSRunObject::InsertBreak(nsCOMPtr<nsIDOMNode> *aInOutParent, 
-                           int32_t *aInOutOffset, 
-                           nsCOMPtr<nsIDOMNode> *outBRNode, 
+already_AddRefed<Element>
+nsWSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
+                           int32_t* aInOutOffset,
                            nsIEditor::EDirection aSelect)
 {
   // MOOSE: for now, we always assume non-PRE formatting.  Fix this later.
-  // meanwhile, the pre case is handled in WillInsertText in nsHTMLEditRules.cpp
-  NS_ENSURE_TRUE(aInOutParent && aInOutOffset && outBRNode, NS_ERROR_NULL_POINTER);
+  // meanwhile, the pre case is handled in WillInsertText in
+  // nsHTMLEditRules.cpp
+  NS_ENSURE_TRUE(aInOutParent && aInOutOffset, nullptr);
 
   nsresult res = NS_OK;
   WSFragment *beforeRun, *afterRun;
-  FindRun(*aInOutParent, *aInOutOffset, &beforeRun, false);
-  FindRun(*aInOutParent, *aInOutOffset, &afterRun, true);
-  
+  FindRun(GetAsDOMNode(*aInOutParent), *aInOutOffset, &beforeRun, false);
+  FindRun(GetAsDOMNode(*aInOutParent), *aInOutOffset, &afterRun, true);
+
   {
-    // some scoping for nsAutoTrackDOMPoint.  This will track our insertion point
-    // while we tweak any surrounding whitespace
-    nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, aInOutParent, aInOutOffset);
+    // Some scoping for nsAutoTrackDOMPoint.  This will track our insertion
+    // point while we tweak any surrounding whitespace
+    nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, aInOutParent,
+                                aInOutOffset);
 
-    // handle any changes needed to ws run after inserted br
-    if (!afterRun) {
-      // don't need to do anything.  just insert break.  ws won't change.
-    } else if (afterRun->mType & WSType::trailingWS) {
-      // don't need to do anything.  just insert break.  ws won't change.
+    // Handle any changes needed to ws run after inserted br
+    if (!afterRun || (afterRun->mType & WSType::trailingWS)) {
+      // Don't need to do anything.  Just insert break.  ws won't change.
     } else if (afterRun->mType & WSType::leadingWS) {
-      // delete the leading ws that is after insertion point.  We don't
-      // have to (it would still not be significant after br), but it's 
+      // Delete the leading ws that is after insertion point.  We don't
+      // have to (it would still not be significant after br), but it's
       // just more aesthetically pleasing to.
-      res = DeleteChars(*aInOutParent, *aInOutOffset, afterRun->mEndNode, afterRun->mEndOffset,
+      res = DeleteChars(GetAsDOMNode(*aInOutParent), *aInOutOffset,
+                        GetAsDOMNode(afterRun->mEndNode), afterRun->mEndOffset,
                         eOutsideUserSelectAll);
-      NS_ENSURE_SUCCESS(res, res);
+      NS_ENSURE_SUCCESS(res, nullptr);
     } else if (afterRun->mType == WSType::normalWS) {
-      // need to determine if break at front of non-nbsp run.  if so
-      // convert run to nbsp.
-      WSPoint thePoint = GetCharAfter(*aInOutParent, *aInOutOffset);
+      // Need to determine if break at front of non-nbsp run.  If so, convert
+      // run to nbsp.
+      WSPoint thePoint = GetCharAfter(GetAsDOMNode(*aInOutParent), *aInOutOffset);
       if (thePoint.mTextNode && nsCRT::IsAsciiSpace(thePoint.mChar)) {
         WSPoint prevPoint = GetCharBefore(thePoint);
         if (prevPoint.mTextNode && !nsCRT::IsAsciiSpace(prevPoint.mChar)) {
-          // we are at start of non-nbsps.  convert to a single nbsp.
+          // We are at start of non-nbsps.  Convert to a single nbsp.
           res = ConvertToNBSP(thePoint);
-          NS_ENSURE_SUCCESS(res, res);
+          NS_ENSURE_SUCCESS(res, nullptr);
         }
       }
     }
-    
-    // handle any changes needed to ws run before inserted br
-    if (!beforeRun) {
-      // don't need to do anything.  just insert break.  ws won't change.
-    } else if (beforeRun->mType & WSType::leadingWS) {
-      // don't need to do anything.  just insert break.  ws won't change.
+
+    // Handle any changes needed to ws run before inserted br
+    if (!beforeRun || (beforeRun->mType & WSType::leadingWS)) {
+      // Don't need to do anything.  Just insert break.  ws won't change.
     } else if (beforeRun->mType & WSType::trailingWS) {
-      // need to delete the trailing ws that is before insertion point, because it 
+      // Need to delete the trailing ws that is before insertion point, because it
       // would become significant after break inserted.
-      res = DeleteChars(beforeRun->mStartNode, beforeRun->mStartOffset, *aInOutParent, *aInOutOffset,
+      res = DeleteChars(GetAsDOMNode(beforeRun->mStartNode), beforeRun->mStartOffset,
+                        GetAsDOMNode(*aInOutParent), *aInOutOffset,
                         eOutsideUserSelectAll);
-      NS_ENSURE_SUCCESS(res, res);
+      NS_ENSURE_SUCCESS(res, nullptr);
     } else if (beforeRun->mType == WSType::normalWS) {
-      // try to change an nbsp to a space, if possible, just to prevent nbsp proliferation
-      res = CheckTrailingNBSP(beforeRun, *aInOutParent, *aInOutOffset);
-      NS_ENSURE_SUCCESS(res, res);
+      // Try to change an nbsp to a space, just to prevent nbsp proliferation
+      res = CheckTrailingNBSP(beforeRun, GetAsDOMNode(*aInOutParent), *aInOutOffset);
+      NS_ENSURE_SUCCESS(res, nullptr);
     }
   }
-  
+
   // ready, aim, fire!
-  return mHTMLEditor->CreateBRImpl(aInOutParent, aInOutOffset, outBRNode, aSelect);
+  return mHTMLEditor->CreateBRImpl(aInOutParent, aInOutOffset, aSelect);
 }
 
 nsresult 
 nsWSRunObject::InsertText(const nsAString& aStringToInsert, 
                           nsCOMPtr<nsIDOMNode> *aInOutParent, 
                           int32_t *aInOutOffset,
                           nsIDOMDocument *aDoc)
 {
@@ -255,34 +311,34 @@ nsWSRunObject::InsertText(const nsAStrin
     // handle any changes needed to ws run after inserted text
     if (!afterRun) {
       // don't need to do anything.  just insert text.  ws won't change.
     } else if (afterRun->mType & WSType::trailingWS) {
       // don't need to do anything.  just insert text.  ws won't change.
     } else if (afterRun->mType & WSType::leadingWS) {
       // delete the leading ws that is after insertion point, because it 
       // would become significant after text inserted.
-      res = DeleteChars(*aInOutParent, *aInOutOffset, afterRun->mEndNode, afterRun->mEndOffset,
+      res = DeleteChars(*aInOutParent, *aInOutOffset, GetAsDOMNode(afterRun->mEndNode), afterRun->mEndOffset,
                          eOutsideUserSelectAll);
       NS_ENSURE_SUCCESS(res, res);
     } else if (afterRun->mType == WSType::normalWS) {
       // try to change an nbsp to a space, if possible, just to prevent nbsp proliferation
       res = CheckLeadingNBSP(afterRun, *aInOutParent, *aInOutOffset);
       NS_ENSURE_SUCCESS(res, res);
     }
     
     // handle any changes needed to ws run before inserted text
     if (!beforeRun) {
       // don't need to do anything.  just insert text.  ws won't change.
     } else if (beforeRun->mType & WSType::leadingWS) {
       // don't need to do anything.  just insert text.  ws won't change.
     } else if (beforeRun->mType & WSType::trailingWS) {
       // need to delete the trailing ws that is before insertion point, because it 
       // would become significant after text inserted.
-      res = DeleteChars(beforeRun->mStartNode, beforeRun->mStartOffset, *aInOutParent, *aInOutOffset,
+      res = DeleteChars(GetAsDOMNode(beforeRun->mStartNode), beforeRun->mStartOffset, *aInOutParent, *aInOutOffset,
                         eOutsideUserSelectAll);
       NS_ENSURE_SUCCESS(res, res);
     } else if (beforeRun->mType == WSType::normalWS) {
       // try to change an nbsp to a space, if possible, just to prevent nbsp proliferation
       res = CheckTrailingNBSP(beforeRun, *aInOutParent, *aInOutOffset);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
@@ -364,70 +420,70 @@ nsWSRunObject::InsertText(const nsAStrin
   // ready, aim, fire!
   res = mHTMLEditor->InsertTextImpl(theString, aInOutParent, aInOutOffset, aDoc);
   return NS_OK;
 }
 
 nsresult 
 nsWSRunObject::DeleteWSBackward()
 {
-  nsresult res = NS_OK;
-  WSPoint point = GetCharBefore(mNode, mOffset);
+  WSPoint point = GetCharBefore(GetAsDOMNode(mNode), mOffset);
   NS_ENSURE_TRUE(point.mTextNode, NS_OK);  // nothing to delete
   
-  if (mPRE)  // easy case, preformatted ws
-  {
-    if (nsCRT::IsAsciiSpace(point.mChar) || (point.mChar == nbsp))
-    {
-      nsCOMPtr<nsIDOMNode> node(do_QueryInterface(point.mTextNode));
-      int32_t startOffset = point.mOffset;
-      int32_t endOffset = point.mOffset+1;
-      return DeleteChars(node, startOffset, node, endOffset);
+  if (mPRE) {
+    // easy case, preformatted ws
+    if (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == nbsp) {
+      return DeleteChars(GetAsDOMNode(point.mTextNode), point.mOffset,
+                         GetAsDOMNode(point.mTextNode), point.mOffset + 1);
     }
   }
   
-  // callers job to insure that previous char is really ws.
-  // If it is normal ws, we need to delete the whole run
-  if (nsCRT::IsAsciiSpace(point.mChar))
-  {
-    nsCOMPtr<nsIDOMNode> startNode, endNode, node(do_QueryInterface(point.mTextNode));
+  // Caller's job to ensure that previous char is really ws.  If it is normal
+  // ws, we need to delete the whole run.
+  if (nsCRT::IsAsciiSpace(point.mChar)) {
+    nsCOMPtr<Text> startNodeText, endNodeText;
     int32_t startOffset, endOffset;
-    GetAsciiWSBounds(eBoth, node, point.mOffset+1, address_of(startNode),
-                     &startOffset, address_of(endNode), &endOffset);
+    GetAsciiWSBounds(eBoth, point.mTextNode, point.mOffset + 1,
+                     getter_AddRefs(startNodeText), &startOffset,
+                     getter_AddRefs(endNodeText), &endOffset);
     
     // adjust surrounding ws
-    res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, address_of(startNode), &startOffset, 
-                                              address_of(endNode), &endOffset);
+    nsCOMPtr<nsINode> startNode = startNodeText.get();
+    nsCOMPtr<nsINode> endNode = endNodeText.get();
+    nsresult res =
+      nsWSRunObject::PrepareToDeleteRange(mHTMLEditor,
+                                          address_of(startNode), &startOffset,
+                                          address_of(endNode), &endOffset);
     NS_ENSURE_SUCCESS(res, res);
     
     // finally, delete that ws
-    return DeleteChars(startNode, startOffset, endNode, endOffset);
-  }
-  else if (point.mChar == nbsp)
-  {
-    nsCOMPtr<nsIDOMNode> node(do_QueryInterface(point.mTextNode));
+    return DeleteChars(GetAsDOMNode(startNode), startOffset,
+                       GetAsDOMNode(endNode), endOffset);
+  } else if (point.mChar == nbsp) {
+    nsCOMPtr<nsINode> node(point.mTextNode);
     // adjust surrounding ws
     int32_t startOffset = point.mOffset;
-    int32_t endOffset = point.mOffset+1;
-    res = nsWSRunObject::PrepareToDeleteRange(mHTMLEditor, address_of(node), &startOffset, 
-                                              address_of(node), &endOffset);
+    int32_t endOffset = point.mOffset + 1;
+    nsresult res =
+      nsWSRunObject::PrepareToDeleteRange(mHTMLEditor,
+                                          address_of(node), &startOffset,
+                                          address_of(node), &endOffset);
     NS_ENSURE_SUCCESS(res, res);
     
     // finally, delete that ws
-    return DeleteChars(node, startOffset, node, endOffset);
-  
+    return DeleteChars(GetAsDOMNode(node), startOffset, GetAsDOMNode(node), endOffset);
   }
   return NS_OK;
 }
 
 nsresult 
 nsWSRunObject::DeleteWSForward()
 {
   nsresult res = NS_OK;
-  WSPoint point = GetCharAfter(mNode, mOffset);
+  WSPoint point = GetCharAfter(GetAsDOMNode(mNode), mOffset);
   NS_ENSURE_TRUE(point.mTextNode, NS_OK);  // nothing to delete
   
   if (mPRE)  // easy case, preformatted ws
   {
     if (nsCRT::IsAsciiSpace(point.mChar) || (point.mChar == nbsp))
     {
       nsCOMPtr<nsIDOMNode> node(do_QueryInterface(point.mTextNode));
       int32_t startOffset = point.mOffset;
@@ -511,17 +567,17 @@ nsWSRunObject::PriorVisibleNode(nsIDOMNo
       }
       // else if no text node then keep looking.  We should eventually fall out of loop
     }
 
     run = run->mLeft;
   }
   
   // if we get here then nothing in ws data to find.  return start reason
-  *outVisNode = mStartReasonNode;
+  *outVisNode = GetAsDOMNode(mStartReasonNode);
   *outVisOffset = mStartOffset;  // this really isn't meaningful if mStartReasonNode!=mStartNode
   *outType = mStartReason;
 }
 
 
 void
 nsWSRunObject::NextVisibleNode (nsIDOMNode *aNode, 
                                 int32_t aOffset, 
@@ -562,17 +618,17 @@ nsWSRunObject::NextVisibleNode (nsIDOMNo
       }
       // else if no text node then keep looking.  We should eventually fall out of loop
     }
 
     run = run->mRight;
   }
   
   // if we get here then nothing in ws data to find.  return end reason
-  *outVisNode = mEndReasonNode;
+  *outVisNode = GetAsDOMNode(mEndReasonNode);
   *outVisOffset = mEndOffset; // this really isn't meaningful if mEndReasonNode!=mEndNode
   *outType = mEndReason;
 }
 
 nsresult 
 nsWSRunObject::AdjustWhitespace()
 {
   // this routine examines a run of ws and tries to get rid of some unneeded nbsp's,
@@ -596,321 +652,278 @@ nsWSRunObject::AdjustWhitespace()
   return res;
 }
 
 
 //--------------------------------------------------------------------------------------------
 //   protected methods
 //--------------------------------------------------------------------------------------------
 
-already_AddRefed<nsIDOMNode>
+already_AddRefed<nsINode>
 nsWSRunObject::GetWSBoundingParent()
 {
   NS_ENSURE_TRUE(mNode, nullptr);
-  nsCOMPtr<nsIDOMNode> wsBoundingParent = mNode;
-  while (!IsBlockNode(wsBoundingParent))
-  {
-    nsCOMPtr<nsIDOMNode> parent;
-    wsBoundingParent->GetParentNode(getter_AddRefs(parent));
-    if (!parent || !mHTMLEditor->IsEditable(parent))
+  nsCOMPtr<nsINode> wsBoundingParent = mNode;
+  while (!IsBlockNode(wsBoundingParent)) {
+    nsCOMPtr<nsINode> parent = wsBoundingParent->GetParentNode();
+    if (!parent || !mHTMLEditor->IsEditable(parent)) {
       break;
+    }
     wsBoundingParent.swap(parent);
   }
   return wsBoundingParent.forget();
 }
 
 nsresult
 nsWSRunObject::GetWSNodes()
 {
   // collect up an array of nodes that are contiguous with the insertion point
   // and which contain only whitespace.  Stop if you reach non-ws text or a new 
   // block boundary.
   nsresult res = NS_OK;
   
-  DOMPoint start(mNode, mOffset), end(mNode, mOffset);
-  nsCOMPtr<nsIDOMNode> wsBoundingParent = GetWSBoundingParent();
+  ::DOMPoint start(mNode, mOffset), end(mNode, mOffset);
+  nsCOMPtr<nsINode> wsBoundingParent = GetWSBoundingParent();
 
   // first look backwards to find preceding ws nodes
-  if (mHTMLEditor->IsTextNode(mNode))
-  {
+  if (mNode->NodeType() == nsIDOMNode::TEXT_NODE) {
     nsCOMPtr<nsIContent> textNode(do_QueryInterface(mNode));
-    const nsTextFragment *textFrag = textNode->GetText();
+    const nsTextFragment* textFrag = textNode->GetText();
     
     res = PrependNodeToList(mNode);
     NS_ENSURE_SUCCESS(res, res);
-    if (mOffset)
-    {
-      int32_t pos;
-      for (pos=mOffset-1; pos>=0; pos--)
-      {
+    if (mOffset) {
+      for (int32_t pos = mOffset - 1; pos >= 0; pos--) {
         // sanity bounds check the char position.  bug 136165
-        if (uint32_t(pos) >= textFrag->GetLength())
-        {
+        if (uint32_t(pos) >= textFrag->GetLength()) {
           NS_NOTREACHED("looking beyond end of text fragment");
           continue;
         }
         char16_t theChar = textFrag->CharAt(pos);
-        if (!nsCRT::IsAsciiSpace(theChar))
-        {
-          if (theChar != nbsp)
-          {
+        if (!nsCRT::IsAsciiSpace(theChar)) {
+          if (theChar != nbsp) {
             mStartNode = mNode;
-            mStartOffset = pos+1;
+            mStartOffset = pos + 1;
             mStartReason = WSType::text;
             mStartReasonNode = mNode;
             break;
           }
           // as we look backwards update our earliest found nbsp
           mFirstNBSPNode = mNode;
           mFirstNBSPOffset = pos;
           // also keep track of latest nbsp so far
-          if (!mLastNBSPNode)
-          {
+          if (!mLastNBSPNode) {
             mLastNBSPNode = mNode;
             mLastNBSPOffset = pos;
           }
         }
-        start.SetPoint(mNode,pos);
+        start.node = mNode;
+        start.offset = pos;
       }
     }
   }
 
-  nsCOMPtr<nsIDOMNode> priorNode;
-  while (!mStartNode)
-  {
+  while (!mStartNode) {
     // we haven't found the start of ws yet.  Keep looking
+    nsCOMPtr<nsINode> priorNode;
     res = GetPreviousWSNode(start, wsBoundingParent, address_of(priorNode));
     NS_ENSURE_SUCCESS(res, res);
-    if (priorNode)
-    {
-      if (IsBlockNode(priorNode))
-      {
-        start.GetPoint(mStartNode, mStartOffset);
+    if (priorNode) {
+      if (IsBlockNode(priorNode)) {
+        mStartNode = start.node;
+        mStartOffset = start.offset;
         mStartReason = WSType::otherBlock;
         mStartReasonNode = priorNode;
       }
-      else if (mHTMLEditor->IsTextNode(priorNode))
-      {
+      else if (priorNode->NodeType() == nsIDOMNode::TEXT_NODE) {
         res = PrependNodeToList(priorNode);
         NS_ENSURE_SUCCESS(res, res);
         nsCOMPtr<nsIContent> textNode(do_QueryInterface(priorNode));
         const nsTextFragment *textFrag;
         if (!textNode || !(textFrag = textNode->GetText())) {
           return NS_ERROR_NULL_POINTER;
         }
         uint32_t len = textNode->TextLength();
 
-        if (len < 1)
-        {
+        if (len < 1) {
           // Zero length text node. Set start point to it
           // so we can get past it!
-          start.SetPoint(priorNode,0);
-        }
-        else
-        {
-          int32_t pos;
-          for (pos=len-1; pos>=0; pos--)
-          {
+          start.SetPoint(priorNode, 0);
+        } else {
+          for (int32_t pos = len - 1; pos >= 0; pos--) {
             // sanity bounds check the char position.  bug 136165
-            if (uint32_t(pos) >= textFrag->GetLength())
-            {
+            if (uint32_t(pos) >= textFrag->GetLength()) {
               NS_NOTREACHED("looking beyond end of text fragment");
               continue;
             }
             char16_t theChar = textFrag->CharAt(pos);
-            if (!nsCRT::IsAsciiSpace(theChar))
-            {
-              if (theChar != nbsp)
-              {
+            if (!nsCRT::IsAsciiSpace(theChar)) {
+              if (theChar != nbsp) {
                 mStartNode = priorNode;
-                mStartOffset = pos+1;
+                mStartOffset = pos + 1;
                 mStartReason = WSType::text;
                 mStartReasonNode = priorNode;
                 break;
               }
               // as we look backwards update our earliest found nbsp
               mFirstNBSPNode = priorNode;
               mFirstNBSPOffset = pos;
               // also keep track of latest nbsp so far
-              if (!mLastNBSPNode)
-              {
+              if (!mLastNBSPNode) {
                 mLastNBSPNode = priorNode;
                 mLastNBSPOffset = pos;
               }
             }
-            start.SetPoint(priorNode,pos);
+            start.SetPoint(priorNode, pos);
           }
         }
-      }
-      else
-      {
+      } else {
         // it's a break or a special node, like <img>, that is not a block and not
         // a break but still serves as a terminator to ws runs.
-        start.GetPoint(mStartNode, mStartOffset);
-        if (nsTextEditUtils::IsBreak(priorNode))
+        mStartNode = start.node;
+        mStartOffset = start.offset;
+        if (nsTextEditUtils::IsBreak(priorNode)) {
           mStartReason = WSType::br;
-        else
+        } else {
           mStartReason = WSType::special;
+        }
         mStartReasonNode = priorNode;
       }
-    }
-    else
-    {
+    } else {
       // no prior node means we exhausted wsBoundingParent
-      start.GetPoint(mStartNode, mStartOffset);
+      mStartNode = start.node;
+      mStartOffset = start.offset;
       mStartReason = WSType::thisBlock;
       mStartReasonNode = wsBoundingParent;
     } 
   }
   
   // then look ahead to find following ws nodes
-  if (mHTMLEditor->IsTextNode(mNode))
-  {
+  if (mNode->NodeType() == nsIDOMNode::TEXT_NODE) {
     // don't need to put it on list. it already is from code above
     nsCOMPtr<nsIContent> textNode(do_QueryInterface(mNode));
     const nsTextFragment *textFrag = textNode->GetText();
 
     uint32_t len = textNode->TextLength();
-    if (uint16_t(mOffset)<len)
-    {
-      int32_t pos;
-      for (pos=mOffset; uint32_t(pos)<len; pos++)
-      {
+    if (uint16_t(mOffset)<len) {
+      for (uint32_t pos = mOffset; pos < len; pos++) {
         // sanity bounds check the char position.  bug 136165
-        if ((pos<0) || (uint32_t(pos)>=textFrag->GetLength()))
-        {
+        if (pos >= textFrag->GetLength()) {
           NS_NOTREACHED("looking beyond end of text fragment");
           continue;
         }
         char16_t theChar = textFrag->CharAt(pos);
-        if (!nsCRT::IsAsciiSpace(theChar))
-        {
-          if (theChar != nbsp)
-          {
+        if (!nsCRT::IsAsciiSpace(theChar)) {
+          if (theChar != nbsp) {
             mEndNode = mNode;
             mEndOffset = pos;
             mEndReason = WSType::text;
             mEndReasonNode = mNode;
             break;
           }
           // as we look forwards update our latest found nbsp
           mLastNBSPNode = mNode;
           mLastNBSPOffset = pos;
           // also keep track of earliest nbsp so far
-          if (!mFirstNBSPNode)
-          {
+          if (!mFirstNBSPNode) {
             mFirstNBSPNode = mNode;
             mFirstNBSPOffset = pos;
           }
         }
-        end.SetPoint(mNode,pos+1);
+        end.SetPoint(mNode, pos + 1);
       }
     }
   }
 
-  nsCOMPtr<nsIDOMNode> nextNode;
-  while (!mEndNode)
-  {
+  while (!mEndNode) {
     // we haven't found the end of ws yet.  Keep looking
+    nsCOMPtr<nsINode> nextNode;
     res = GetNextWSNode(end, wsBoundingParent, address_of(nextNode));
     NS_ENSURE_SUCCESS(res, res);
-    if (nextNode)
-    {
-      if (IsBlockNode(nextNode))
-      {
+    if (nextNode) {
+      if (IsBlockNode(nextNode)) {
         // we encountered a new block.  therefore no more ws.
-        end.GetPoint(mEndNode, mEndOffset);
+        mEndNode = end.node;
+        mEndOffset = end.offset;
         mEndReason = WSType::otherBlock;
         mEndReasonNode = nextNode;
-      }
-      else if (mHTMLEditor->IsTextNode(nextNode))
-      {
+      } else if (mHTMLEditor->IsTextNode(nextNode)) {
         res = AppendNodeToList(nextNode);
         NS_ENSURE_SUCCESS(res, res);
         nsCOMPtr<nsIContent> textNode(do_QueryInterface(nextNode));
         const nsTextFragment *textFrag;
         if (!textNode || !(textFrag = textNode->GetText())) {
           return NS_ERROR_NULL_POINTER;
         }
         uint32_t len = textNode->TextLength();
 
-        if (len < 1)
-        {
+        if (len < 1) {
           // Zero length text node. Set end point to it
           // so we can get past it!
           end.SetPoint(nextNode,0);
-        }
-        else
-        {
-          int32_t pos;
-          for (pos=0; uint32_t(pos)<len; pos++)
-          {
+        } else {
+          for (uint32_t pos = 0; pos < len; pos++) {
             // sanity bounds check the char position.  bug 136165
-            if (uint32_t(pos) >= textFrag->GetLength())
-            {
+            if (pos >= textFrag->GetLength()) {
               NS_NOTREACHED("looking beyond end of text fragment");
               continue;
             }
             char16_t theChar = textFrag->CharAt(pos);
-            if (!nsCRT::IsAsciiSpace(theChar))
-            {
-              if (theChar != nbsp)
-              {
+            if (!nsCRT::IsAsciiSpace(theChar)) {
+              if (theChar != nbsp) {
                 mEndNode = nextNode;
                 mEndOffset = pos;
                 mEndReason = WSType::text;
                 mEndReasonNode = nextNode;
                 break;
               }
               // as we look forwards update our latest found nbsp
               mLastNBSPNode = nextNode;
               mLastNBSPOffset = pos;
               // also keep track of earliest nbsp so far
-              if (!mFirstNBSPNode)
-              {
+              if (!mFirstNBSPNode) {
                 mFirstNBSPNode = nextNode;
                 mFirstNBSPOffset = pos;
               }
             }
-            end.SetPoint(nextNode,pos+1);
+            end.SetPoint(nextNode, pos + 1);
           }
         }
-      }
-      else
-      {
+      } else {
         // we encountered a break or a special node, like <img>, 
         // that is not a block and not a break but still 
         // serves as a terminator to ws runs.
-        end.GetPoint(mEndNode, mEndOffset);
-        if (nsTextEditUtils::IsBreak(nextNode))
+        mEndNode = end.node;
+        mEndOffset = end.offset;
+        if (nsTextEditUtils::IsBreak(nextNode)) {
           mEndReason = WSType::br;
-        else
+        } else {
           mEndReason = WSType::special;
+        }
         mEndReasonNode = nextNode;
       }
-    }
-    else
-    {
+    } else {
       // no next node means we exhausted wsBoundingParent
-      end.GetPoint(mEndNode, mEndOffset);
+      mEndNode = end.node;
+      mEndOffset = end.offset;
       mEndReason = WSType::thisBlock;
       mEndReasonNode = wsBoundingParent;
     } 
   }
 
   return NS_OK;
 }
 
 void
 nsWSRunObject::GetRuns()
 {
   ClearRuns();
   
   // handle some easy cases first
-  mHTMLEditor->IsPreformatted(mNode, &mPRE);
+  mHTMLEditor->IsPreformatted(GetAsDOMNode(mNode), &mPRE);
   // if it's preformatedd, or if we are surrounded by text or special, it's all one
   // big normal ws run
   if (mPRE ||
       ((mStartReason == WSType::text || mStartReason == WSType::special) &&
        (mEndReason == WSType::text || mEndReason == WSType::special ||
         mEndReason == WSType::br))) {
     MakeSingleWSRun(WSType::normalWS);
     return;
@@ -1056,239 +1069,210 @@ nsWSRunObject::MakeSingleWSRun(WSType aT
   mStartRun->mEndOffset   = mEndOffset;
   mStartRun->mLeftType    = mStartReason;
   mStartRun->mRightType   = mEndReason;
   
   mEndRun  = mStartRun;
 }
 
 nsresult 
-nsWSRunObject::PrependNodeToList(nsIDOMNode *aNode)
+nsWSRunObject::PrependNodeToList(nsINode *aNode)
 {
   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
-  if (!mNodeArray.InsertObjectAt(aNode, 0))
+  if (!mNodeArray.InsertObjectAt(aNode, 0)) {
     return NS_ERROR_FAILURE;
+  }
   return NS_OK;
 }
 
 nsresult 
-nsWSRunObject::AppendNodeToList(nsIDOMNode *aNode)
+nsWSRunObject::AppendNodeToList(nsINode* aNode)
 {
   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
-  if (!mNodeArray.AppendObject(aNode))
+  if (!mNodeArray.AppendObject(aNode)) {
     return NS_ERROR_FAILURE;
+  }
   return NS_OK;
 }
 
 nsresult 
-nsWSRunObject::GetPreviousWSNode(nsIDOMNode *aStartNode, 
-                                 nsIDOMNode *aBlockParent, 
-                                 nsCOMPtr<nsIDOMNode> *aPriorNode)
+nsWSRunObject::GetPreviousWSNodeInner(nsINode* aStartNode,
+                                      nsINode* aBlockParent,
+                                      nsCOMPtr<nsINode>* aPriorNode)
 {
-  // can't really recycle various getnext/prior routines because we
-  // have special needs here.  Need to step into inline containers but
-  // not block containers.
+  // can't really recycle various getnext/prior routines because we have
+  // special needs here.  Need to step into inline containers but not block
+  // containers.
   NS_ENSURE_TRUE(aStartNode && aBlockParent && aPriorNode, NS_ERROR_NULL_POINTER);
   
-  nsresult res = aStartNode->GetPreviousSibling(getter_AddRefs(*aPriorNode));
-  NS_ENSURE_SUCCESS(res, res);
-  nsCOMPtr<nsIDOMNode> temp, curNode = aStartNode;
-  while (!*aPriorNode)
-  {
+  *aPriorNode = aStartNode->GetPreviousSibling();
+  nsCOMPtr<nsINode> temp, curNode(aStartNode);
+  while (!*aPriorNode) {
     // we have exhausted nodes in parent of aStartNode.
-    res = curNode->GetParentNode(getter_AddRefs(temp));
-    NS_ENSURE_SUCCESS(res, res);
+    temp = curNode->GetParentNode();
     NS_ENSURE_TRUE(temp, NS_ERROR_NULL_POINTER);
-    if (temp == aBlockParent)
-    {
-      // we have exhausted nodes in the block parent.  The convention here is to return null.
+    if (temp == aBlockParent) {
+      // we have exhausted nodes in the block parent.  The convention here is
+      // to return null.
       *aPriorNode = nullptr;
       return NS_OK;
     }
     // we have a parent: look for previous sibling
-    res = temp->GetPreviousSibling(getter_AddRefs(*aPriorNode));
-    NS_ENSURE_SUCCESS(res, res);
+    *aPriorNode = temp->GetPreviousSibling();
     curNode = temp;
   }
   // we have a prior node.  If it's a block, return it.
-  if (IsBlockNode(*aPriorNode))
+  if (IsBlockNode(*aPriorNode)) {
     return NS_OK;
-  // else if it's a container, get deep rightmost child
-  else if (mHTMLEditor->IsContainer(*aPriorNode))
-  {
+  } else if (mHTMLEditor->IsContainer(*aPriorNode)) {
+    // else if it's a container, get deep rightmost child
     temp = mHTMLEditor->GetRightmostChild(*aPriorNode);
-    if (temp)
+    if (temp) {
       *aPriorNode = temp;
+    }
     return NS_OK;
   }
   // else return the node itself
   return NS_OK;
 }
 
 nsresult 
-nsWSRunObject::GetPreviousWSNode(DOMPoint aPoint,
-                                 nsIDOMNode *aBlockParent, 
-                                 nsCOMPtr<nsIDOMNode> *aPriorNode)
-{
-  nsCOMPtr<nsIDOMNode> node;
-  int32_t offset;
-  aPoint.GetPoint(node, offset);
-  return GetPreviousWSNode(node,offset,aBlockParent,aPriorNode);
-}
-
-nsresult 
-nsWSRunObject::GetPreviousWSNode(nsIDOMNode *aStartNode,
-                                 int32_t aOffset,
-                                 nsIDOMNode *aBlockParent, 
-                                 nsCOMPtr<nsIDOMNode> *aPriorNode)
+nsWSRunObject::GetPreviousWSNode(::DOMPoint aPoint,
+                                 nsINode* aBlockParent,
+                                 nsCOMPtr<nsINode>* aPriorNode)
 {
   // can't really recycle various getnext/prior routines because we
   // have special needs here.  Need to step into inline containers but
   // not block containers.
-  NS_ENSURE_TRUE(aStartNode && aBlockParent && aPriorNode, NS_ERROR_NULL_POINTER);
-  *aPriorNode = 0;
+  NS_ENSURE_TRUE(aPoint.node && aBlockParent && aPriorNode,
+                 NS_ERROR_NULL_POINTER);
+  *aPriorNode = nullptr;
 
-  if (mHTMLEditor->IsTextNode(aStartNode))
-    return GetPreviousWSNode(aStartNode, aBlockParent, aPriorNode);
-  if (!mHTMLEditor->IsContainer(aStartNode))
-    return GetPreviousWSNode(aStartNode, aBlockParent, aPriorNode);
+  if (aPoint.node->NodeType() == nsIDOMNode::TEXT_NODE) {
+    return GetPreviousWSNodeInner(aPoint.node, aBlockParent, aPriorNode);
+  }
+  if (!mHTMLEditor->IsContainer(aPoint.node)) {
+    return GetPreviousWSNodeInner(aPoint.node, aBlockParent, aPriorNode);
+  }
   
-  if (!aOffset)
-  {
-    if (aStartNode==aBlockParent)
-    {
+  if (!aPoint.offset) {
+    if (aPoint.node == aBlockParent) {
       // we are at start of the block.
       return NS_OK;
     }
 
     // we are at start of non-block container
-    return GetPreviousWSNode(aStartNode, aBlockParent, aPriorNode);
+    return GetPreviousWSNodeInner(aPoint.node, aBlockParent, aPriorNode);
   }
 
-  nsCOMPtr<nsIContent> startContent( do_QueryInterface(aStartNode) );
+  nsCOMPtr<nsIContent> startContent(do_QueryInterface(aPoint.node));
   NS_ENSURE_STATE(startContent);
-  nsIContent *priorContent = startContent->GetChildAt(aOffset - 1);
+  nsIContent* priorContent = startContent->GetChildAt(aPoint.offset - 1);
   NS_ENSURE_TRUE(priorContent, NS_ERROR_NULL_POINTER);
-  *aPriorNode = do_QueryInterface(priorContent);
+  *aPriorNode = priorContent;
   // we have a prior node.  If it's a block, return it.
-  if (IsBlockNode(*aPriorNode))
+  if (IsBlockNode(*aPriorNode)) {
     return NS_OK;
-  // else if it's a container, get deep rightmost child
-  else if (mHTMLEditor->IsContainer(*aPriorNode))
-  {
-    nsCOMPtr<nsIDOMNode> temp;
+  } else if (mHTMLEditor->IsContainer(*aPriorNode)) {
+    // else if it's a container, get deep rightmost child
+    nsCOMPtr<nsINode> temp;
     temp = mHTMLEditor->GetRightmostChild(*aPriorNode);
-    if (temp)
+    if (temp) {
       *aPriorNode = temp;
+    }
     return NS_OK;
   }
   // else return the node itself
   return NS_OK;
 }
 
 nsresult 
-nsWSRunObject::GetNextWSNode(nsIDOMNode *aStartNode, 
-                             nsIDOMNode *aBlockParent, 
-                             nsCOMPtr<nsIDOMNode> *aNextNode)
+nsWSRunObject::GetNextWSNodeInner(nsINode* aStartNode,
+                                  nsINode* aBlockParent,
+                                  nsCOMPtr<nsINode>* aNextNode)
 {
-  // can't really recycle various getnext/prior routines because we
-  // have special needs here.  Need to step into inline containers but
-  // not block containers.
-  NS_ENSURE_TRUE(aStartNode && aBlockParent && aNextNode, NS_ERROR_NULL_POINTER);
+  // can't really recycle various getnext/prior routines because we have
+  // special needs here.  Need to step into inline containers but not block
+  // containers.
+  NS_ENSURE_TRUE(aStartNode && aBlockParent && aNextNode,
+                 NS_ERROR_NULL_POINTER);
   
-  *aNextNode = 0;
-  nsresult res = aStartNode->GetNextSibling(getter_AddRefs(*aNextNode));
-  NS_ENSURE_SUCCESS(res, res);
-  nsCOMPtr<nsIDOMNode> temp, curNode = aStartNode;
-  while (!*aNextNode)
-  {
+  *aNextNode = aStartNode->GetNextSibling();
+  nsCOMPtr<nsINode> temp, curNode(aStartNode);
+  while (!*aNextNode) {
     // we have exhausted nodes in parent of aStartNode.
-    res = curNode->GetParentNode(getter_AddRefs(temp));
-    NS_ENSURE_SUCCESS(res, res);
+    temp = curNode->GetParentNode();
     NS_ENSURE_TRUE(temp, NS_ERROR_NULL_POINTER);
-    if (temp == aBlockParent)
-    {
-      // we have exhausted nodes in the block parent.  The convention
-      // here is to return null.
+    if (temp == aBlockParent) {
+      // we have exhausted nodes in the block parent.  The convention here is
+      // to return null.
       *aNextNode = nullptr;
       return NS_OK;
     }
     // we have a parent: look for next sibling
-    res = temp->GetNextSibling(getter_AddRefs(*aNextNode));
-    NS_ENSURE_SUCCESS(res, res);
+    *aNextNode = temp->GetNextSibling();
     curNode = temp;
   }
   // we have a next node.  If it's a block, return it.
-  if (IsBlockNode(*aNextNode))
+  if (IsBlockNode(*aNextNode)) {
     return NS_OK;
-  // else if it's a container, get deep leftmost child
-  else if (mHTMLEditor->IsContainer(*aNextNode))
-  {
+  } else if (mHTMLEditor->IsContainer(*aNextNode)) {
+    // else if it's a container, get deep leftmost child
     temp = mHTMLEditor->GetLeftmostChild(*aNextNode);
-    if (temp)
+    if (temp) {
       *aNextNode = temp;
+    }
     return NS_OK;
   }
   // else return the node itself
   return NS_OK;
 }
 
 nsresult 
-nsWSRunObject::GetNextWSNode(DOMPoint aPoint,
-                             nsIDOMNode *aBlockParent, 
-                             nsCOMPtr<nsIDOMNode> *aNextNode)
-{
-  nsCOMPtr<nsIDOMNode> node;
-  int32_t offset;
-  aPoint.GetPoint(node, offset);
-  return GetNextWSNode(node,offset,aBlockParent,aNextNode);
-}
-
-nsresult 
-nsWSRunObject::GetNextWSNode(nsIDOMNode *aStartNode,
-                             int32_t aOffset,
-                             nsIDOMNode *aBlockParent, 
-                             nsCOMPtr<nsIDOMNode> *aNextNode)
+nsWSRunObject::GetNextWSNode(::DOMPoint aPoint,
+                             nsINode* aBlockParent,
+                             nsCOMPtr<nsINode>* aNextNode)
 {
-  // can't really recycle various getnext/prior routines because we have special needs
-  // here.  Need to step into inline containers but not block containers.
-  NS_ENSURE_TRUE(aStartNode && aBlockParent && aNextNode, NS_ERROR_NULL_POINTER);
-  *aNextNode = 0;
+  // can't really recycle various getnext/prior routines because we have
+  // special needs here.  Need to step into inline containers but not block
+  // containers.
+  NS_ENSURE_TRUE(aPoint.node && aBlockParent && aNextNode,
+                 NS_ERROR_NULL_POINTER);
+  *aNextNode = nullptr;
 
-  if (mHTMLEditor->IsTextNode(aStartNode))
-    return GetNextWSNode(aStartNode, aBlockParent, aNextNode);
-  if (!mHTMLEditor->IsContainer(aStartNode))
-    return GetNextWSNode(aStartNode, aBlockParent, aNextNode);
+  if (aPoint.node->NodeType() == nsIDOMNode::TEXT_NODE) {
+    return GetNextWSNodeInner(aPoint.node, aBlockParent, aNextNode);
+  }
+  if (!mHTMLEditor->IsContainer(aPoint.node)) {
+    return GetNextWSNodeInner(aPoint.node, aBlockParent, aNextNode);
+  }
   
-  nsCOMPtr<nsIContent> startContent( do_QueryInterface(aStartNode) );
+  nsCOMPtr<nsIContent> startContent(do_QueryInterface(aPoint.node));
   NS_ENSURE_STATE(startContent);
-  nsIContent *nextContent = startContent->GetChildAt(aOffset);
-  if (!nextContent)
-  {
-    if (aStartNode==aBlockParent)
-    {
+  nsIContent *nextContent = startContent->GetChildAt(aPoint.offset);
+  if (!nextContent) {
+    if (aPoint.node == aBlockParent) {
       // we are at end of the block.
       return NS_OK;
     }
 
     // we are at end of non-block container
-    return GetNextWSNode(aStartNode, aBlockParent, aNextNode);
+    return GetNextWSNodeInner(aPoint.node, aBlockParent, aNextNode);
   }
   
-  *aNextNode = do_QueryInterface(nextContent);
+  *aNextNode = nextContent;
   // we have a next node.  If it's a block, return it.
-  if (IsBlockNode(*aNextNode))
+  if (IsBlockNode(*aNextNode)) {
     return NS_OK;
-  // else if it's a container, get deep leftmost child
-  else if (mHTMLEditor->IsContainer(*aNextNode))
-  {
-    nsCOMPtr<nsIDOMNode> temp;
-    temp = mHTMLEditor->GetLeftmostChild(*aNextNode);
-    if (temp)
+  } else if (mHTMLEditor->IsContainer(*aNextNode)) {
+    // else if it's a container, get deep leftmost child
+    nsCOMPtr<nsINode> temp = mHTMLEditor->GetLeftmostChild(*aNextNode);
+    if (temp) {
       *aNextNode = temp;
+    }
     return NS_OK;
   }
   // else return the node itself
   return NS_OK;
 }
 
 nsresult 
 nsWSRunObject::PrepareToDeleteRangePriv(nsWSRunObject* aEndObject)
@@ -1300,63 +1284,58 @@ nsWSRunObject::PrepareToDeleteRangePriv(
   // the deletion, in which case these adjstments are unneeded (though
   // I don't think they can ever be harmful?)
   
   NS_ENSURE_TRUE(aEndObject, NS_ERROR_NULL_POINTER);
   nsresult res = NS_OK;
   
   // get the runs before and after selection
   WSFragment *beforeRun, *afterRun;
-  FindRun(mNode, mOffset, &beforeRun, false);
-  aEndObject->FindRun(aEndObject->mNode, aEndObject->mOffset, &afterRun, true);
+  FindRun(GetAsDOMNode(mNode), mOffset, &beforeRun, false);
+  aEndObject->FindRun(GetAsDOMNode(aEndObject->mNode), aEndObject->mOffset, &afterRun, true);
   
   // trim after run of any leading ws
   if (afterRun && (afterRun->mType & WSType::leadingWS)) {
-    res = aEndObject->DeleteChars(aEndObject->mNode, aEndObject->mOffset, afterRun->mEndNode, afterRun->mEndOffset,
+    res = aEndObject->DeleteChars(GetAsDOMNode(aEndObject->mNode), aEndObject->mOffset, GetAsDOMNode(afterRun->mEndNode), afterRun->mEndOffset,
                                   eOutsideUserSelectAll);
     NS_ENSURE_SUCCESS(res, res);
   }
   // adjust normal ws in afterRun if needed
   if (afterRun && afterRun->mType == WSType::normalWS && !aEndObject->mPRE) {
     if ((beforeRun && (beforeRun->mType & WSType::leadingWS)) ||
         (!beforeRun && ((mStartReason & WSType::block) ||
                         mStartReason == WSType::br))) {
       // make sure leading char of following ws is an nbsp, so that it will show up
-      WSPoint point = aEndObject->GetCharAfter(aEndObject->mNode,
+      WSPoint point = aEndObject->GetCharAfter(GetAsDOMNode(aEndObject->mNode),
                                                aEndObject->mOffset);
       if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
       {
         res = aEndObject->ConvertToNBSP(point, eOutsideUserSelectAll);
         NS_ENSURE_SUCCESS(res, res);
       }
     }
   }
   // trim before run of any trailing ws
   if (beforeRun && (beforeRun->mType & WSType::trailingWS)) {
-    res = DeleteChars(beforeRun->mStartNode, beforeRun->mStartOffset, mNode, mOffset,
+    res = DeleteChars(GetAsDOMNode(beforeRun->mStartNode), beforeRun->mStartOffset, GetAsDOMNode(mNode), mOffset,
                       eOutsideUserSelectAll);
     NS_ENSURE_SUCCESS(res, res);
   } else if (beforeRun && beforeRun->mType == WSType::normalWS && !mPRE) {
     if ((afterRun && (afterRun->mType & WSType::trailingWS)) ||
         (afterRun && afterRun->mType == WSType::normalWS) ||
         (!afterRun && (aEndObject->mEndReason & WSType::block))) {
       // make sure trailing char of starting ws is an nbsp, so that it will show up
-      WSPoint point = GetCharBefore(mNode, mOffset);
+      WSPoint point = GetCharBefore(GetAsDOMNode(mNode), mOffset);
       if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
       {
         nsCOMPtr<nsIDOMNode> wsStartNode, wsEndNode;
         int32_t wsStartOffset, wsEndOffset;
-        GetAsciiWSBounds(eBoth, mNode, mOffset, address_of(wsStartNode),
+        GetAsciiWSBounds(eBoth, GetAsDOMNode(mNode), mOffset, address_of(wsStartNode),
                          &wsStartOffset, address_of(wsEndNode), &wsEndOffset);
         point.mTextNode = do_QueryInterface(wsStartNode);
-        if (!point.mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) {
-          // Not sure if this is needed, but it'll maintain the same
-          // functionality
-          point.mTextNode = nullptr;
-        }
         point.mOffset = wsStartOffset;
         res = ConvertToNBSP(point, eOutsideUserSelectAll);
         NS_ENSURE_SUCCESS(res, res);
       }
     }
   }
   return res;
 }
@@ -1366,46 +1345,41 @@ nsWSRunObject::PrepareToSplitAcrossBlock
 {
   // used to prepare ws to be split across two blocks.  The main issue 
   // here is make sure normalWS doesn't end up becoming non-significant
   // leading or trailing ws after the split.
   nsresult res = NS_OK;
   
   // get the runs before and after selection
   WSFragment *beforeRun, *afterRun;
-  FindRun(mNode, mOffset, &beforeRun, false);
-  FindRun(mNode, mOffset, &afterRun, true);
+  FindRun(GetAsDOMNode(mNode), mOffset, &beforeRun, false);
+  FindRun(GetAsDOMNode(mNode), mOffset, &afterRun, true);
   
   // adjust normal ws in afterRun if needed
   if (afterRun && afterRun->mType == WSType::normalWS) {
     // make sure leading char of following ws is an nbsp, so that it will show up
-    WSPoint point = GetCharAfter(mNode, mOffset);
+    WSPoint point = GetCharAfter(GetAsDOMNode(mNode), mOffset);
     if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
     {
       res = ConvertToNBSP(point);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
 
   // adjust normal ws in beforeRun if needed
   if (beforeRun && beforeRun->mType == WSType::normalWS) {
     // make sure trailing char of starting ws is an nbsp, so that it will show up
-    WSPoint point = GetCharBefore(mNode, mOffset);
+    WSPoint point = GetCharBefore(GetAsDOMNode(mNode), mOffset);
     if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar))
     {
       nsCOMPtr<nsIDOMNode> wsStartNode, wsEndNode;
       int32_t wsStartOffset, wsEndOffset;
-      GetAsciiWSBounds(eBoth, mNode, mOffset, address_of(wsStartNode),
+      GetAsciiWSBounds(eBoth, GetAsDOMNode(mNode), mOffset, address_of(wsStartNode),
                        &wsStartOffset, address_of(wsEndNode), &wsEndOffset);
       point.mTextNode = do_QueryInterface(wsStartNode);
-      if (!point.mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) {
-        // Not sure if this is needed, but it'll maintain the same
-        // functionality
-        point.mTextNode = nullptr;
-      }
       point.mOffset = wsStartOffset;
       res = ConvertToNBSP(point);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
   return res;
 }
 
@@ -1431,17 +1405,18 @@ nsWSRunObject::DeleteChars(nsIDOMNode *a
         return NS_OK;
     }
   }
 
   if ((aStartNode == aEndNode) && (aStartOffset == aEndOffset))
     return NS_OK;  // nothing to delete
   
   nsresult res = NS_OK;
-  int32_t idx = mNodeArray.IndexOf(aStartNode);
+  nsCOMPtr<nsINode> startNode = do_QueryInterface(aStartNode);
+  int32_t idx = mNodeArray.IndexOf(startNode);
   if (idx==-1) idx = 0; // if our strarting point wasn't one of our ws text nodes,
                         // then just go through them from the beginning.
   nsCOMPtr<nsIDOMNode> node;
   nsCOMPtr<nsIDOMCharacterData> textnode;
   nsRefPtr<nsRange> range;
 
   if (aStartNode == aEndNode)
   {
@@ -1451,17 +1426,17 @@ nsWSRunObject::DeleteChars(nsIDOMNode *a
       return mHTMLEditor->DeleteText(textnode, (uint32_t)aStartOffset, 
                                      (uint32_t)(aEndOffset-aStartOffset));
     }
   }
 
   int32_t count = mNodeArray.Count();
   while (idx < count)
   {
-    node = mNodeArray[idx];
+    node = GetAsDOMNode(mNodeArray[idx]);
     if (!node)
       break;  // we ran out of ws nodes; must have been deleting to end
     if (node == aStartNode)
     {
       textnode = do_QueryInterface(node);
       uint32_t len;
       textnode->GetLength(&len);
       if (uint32_t(aStartOffset)<len)
@@ -1499,129 +1474,125 @@ nsWSRunObject::DeleteChars(nsIDOMNode *a
       if (nodeAfter)
       {
         break;
       }
       if (!nodeBefore)
       {
         res = mHTMLEditor->DeleteNode(node);
         NS_ENSURE_SUCCESS(res, res);
-        mNodeArray.RemoveObject(node);
+        nsCOMPtr<nsINode> node_ = do_QueryInterface(node);
+        mNodeArray.RemoveObject(node_);
         --count;
         --idx;
       }
     }
     idx++;
   }
   return res;
 }
 
 nsWSRunObject::WSPoint
 nsWSRunObject::GetCharAfter(nsIDOMNode *aNode, int32_t aOffset)
 {
   MOZ_ASSERT(aNode);
 
-  int32_t idx = mNodeArray.IndexOf(aNode);
+  nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
+  int32_t idx = mNodeArray.IndexOf(node);
   if (idx == -1) 
   {
     // use range comparisons to get right ws node
     return GetWSPointAfter(aNode, aOffset);
   }
   else
   {
     // use wspoint version of GetCharAfter()
-    WSPoint point(aNode,aOffset,0);
+    WSPoint point(node, aOffset, 0);
     return GetCharAfter(point);
   }
 }
 
 nsWSRunObject::WSPoint
 nsWSRunObject::GetCharBefore(nsIDOMNode *aNode, int32_t aOffset)
 {
   MOZ_ASSERT(aNode);
 
-  int32_t idx = mNodeArray.IndexOf(aNode);
+  nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
+  int32_t idx = mNodeArray.IndexOf(node);
   if (idx == -1) 
   {
     // use range comparisons to get right ws node
     return GetWSPointBefore(aNode, aOffset);
   }
   else
   {
     // use wspoint version of GetCharBefore()
-    WSPoint point(aNode,aOffset,0);
+    WSPoint point(node, aOffset, 0);
     return GetCharBefore(point);
   }
 }
 
 nsWSRunObject::WSPoint
 nsWSRunObject::GetCharAfter(const WSPoint &aPoint)
 {
   MOZ_ASSERT(aPoint.mTextNode);
   
   WSPoint outPoint;
   outPoint.mTextNode = nullptr;
   outPoint.mOffset = 0;
   outPoint.mChar = 0;
 
-  nsCOMPtr<nsIDOMNode> pointTextNode(do_QueryInterface(aPoint.mTextNode));
-  int32_t idx = mNodeArray.IndexOf(pointTextNode);
+  int32_t idx = mNodeArray.IndexOf(aPoint.mTextNode);
   if (idx == -1) {
     // can't find point, but it's not an error
     return outPoint;
   }
   int32_t numNodes = mNodeArray.Count();
   
   if (uint16_t(aPoint.mOffset) < aPoint.mTextNode->TextLength())
   {
     outPoint = aPoint;
     outPoint.mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset);
     return outPoint;
   } else if (idx + 1 < (int32_t)numNodes) {
-    nsIDOMNode* node = mNodeArray[idx+1];
+    nsIDOMNode* node = GetAsDOMNode(mNodeArray[idx+1]);
     MOZ_ASSERT(node);
     outPoint.mTextNode = do_QueryInterface(node);
-    if (!outPoint.mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) {
-      // Not sure if this is needed, but it'll maintain the same
-      // functionality
-      outPoint.mTextNode = nullptr;
-    }
     outPoint.mOffset = 0;
     outPoint.mChar = GetCharAt(outPoint.mTextNode, 0);
   }
   return outPoint;
 }
 
 nsWSRunObject::WSPoint
 nsWSRunObject::GetCharBefore(const WSPoint &aPoint)
 {
   MOZ_ASSERT(aPoint.mTextNode);
   
   WSPoint outPoint;
   outPoint.mTextNode = nullptr;
   outPoint.mOffset = 0;
   outPoint.mChar = 0;
   
-  nsCOMPtr<nsIDOMNode> pointTextNode(do_QueryInterface(aPoint.mTextNode));
-  int32_t idx = mNodeArray.IndexOf(pointTextNode);
+  int32_t idx = mNodeArray.IndexOf(aPoint.mTextNode);
   if (idx == -1) {
     // can't find point, but it's not an error
     return outPoint;
   }
   
   if (aPoint.mOffset != 0)
   {
     outPoint = aPoint;
     outPoint.mOffset--;
     outPoint.mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset-1);
     return outPoint;
   }
   else if (idx)
   {
-    nsIDOMNode* node = mNodeArray[idx-1];
+    nsIDOMNode* node = GetAsDOMNode(mNodeArray[idx-1]);
     MOZ_ASSERT(node);
     outPoint.mTextNode = do_QueryInterface(node);
 
     uint32_t len = outPoint.mTextNode->TextLength();
 
     if (len)
     {
       outPoint.mOffset = len-1;
@@ -1671,16 +1642,31 @@ nsWSRunObject::ConvertToNBSP(WSPoint aPo
   {
     res = DeleteChars(startNode, startOffset, endNode, endOffset);
   }
   
   return res;
 }
 
 void
+nsWSRunObject::GetAsciiWSBounds(int16_t aDir, nsINode* aNode, int32_t aOffset,
+                                Text** outStartNode, int32_t* outStartOffset,
+                                Text** outEndNode, int32_t* outEndOffset)
+{
+  nsCOMPtr<nsIDOMNode> outStartDOMNode, outEndDOMNode;
+  GetAsciiWSBounds(aDir, GetAsDOMNode(aNode), aOffset,
+                   address_of(outStartDOMNode), outStartOffset,
+                   address_of(outEndDOMNode), outEndOffset);
+  nsCOMPtr<Text> start(do_QueryInterface(outStartDOMNode));
+  nsCOMPtr<Text> end(do_QueryInterface(outEndDOMNode));
+  start.forget(outStartNode);
+  end.forget(outEndNode);
+}
+
+void
 nsWSRunObject::GetAsciiWSBounds(int16_t aDir, nsIDOMNode *aNode, int32_t aOffset,
                                 nsCOMPtr<nsIDOMNode> *outStartNode, int32_t *outStartOffset,
                                 nsCOMPtr<nsIDOMNode> *outEndNode, int32_t *outEndOffset)
 {
   MOZ_ASSERT(aNode && outStartNode && outEndNode);
 
   nsCOMPtr<nsIDOMNode> startNode, endNode;
   int32_t startOffset=0, endOffset=0;
@@ -1746,32 +1732,32 @@ nsWSRunObject::FindRun(nsIDOMNode *aNode
 {
   *outRun = nullptr;
   // given a dompoint, find the ws run that is before or after it, as caller needs
   MOZ_ASSERT(aNode && outRun);
     
   WSFragment *run = mStartRun;
   while (run)
   {
-    int16_t comp = nsContentUtils::ComparePoints(aNode, aOffset, run->mStartNode,
+    int16_t comp = nsContentUtils::ComparePoints(aNode, aOffset, GetAsDOMNode(run->mStartNode),
                                                  run->mStartOffset);
     if (comp <= 0)
     {
       if (after)
       {
         *outRun = run;
       }
       else // before
       {
         *outRun = nullptr;
       }
       return;
     }
     comp = nsContentUtils::ComparePoints(aNode, aOffset,
-                                         run->mEndNode, run->mEndOffset);
+                                         GetAsDOMNode(run->mEndNode), run->mEndOffset);
     if (comp < 0)
     {
       *outRun = run;
       return;
     }
     else if (comp == 0)
     {
       if (after)
@@ -1834,17 +1820,17 @@ nsWSRunObject::GetWSPointAfter(nsIDOMNod
   int16_t cmp=0;
   nsCOMPtr<nsIDOMNode>  curNode;
   
   // begin binary search
   // we do this because we need to minimize calls to ComparePoints(),
   // which is mongo expensive
   while (curNum != lastNum)
   {
-    curNode = mNodeArray[curNum];
+    curNode = GetAsDOMNode(mNodeArray[curNum]);
     cmp = nsContentUtils::ComparePoints(aNode, aOffset, curNode, 0);
     if (cmp < 0)
       lastNum = curNum;
     else
       firstNum = curNum + 1;
     curNum = (lastNum - firstNum) / 2 + firstNum;
     NS_ASSERTION(firstNum <= curNum && curNum <= lastNum, "Bad binary search");
   }
@@ -1887,17 +1873,17 @@ nsWSRunObject::GetWSPointBefore(nsIDOMNo
   int16_t cmp=0;
   nsCOMPtr<nsIDOMNode>  curNode;
   
   // begin binary search
   // we do this because we need to minimize calls to ComparePoints(),
   // which is mongo expensive
   while (curNum != lastNum)
   {
-    curNode = mNodeArray[curNum];
+    curNode = GetAsDOMNode(mNodeArray[curNum]);
     cmp = nsContentUtils::ComparePoints(aNode, aOffset, curNode, 0);
     if (cmp < 0)
       lastNum = curNum;
     else
       firstNum = curNum + 1;
     curNum = (lastNum - firstNum) / 2 + firstNum;
     NS_ASSERTION(firstNum <= curNum && curNum <= lastNum, "Bad binary search");
   }
@@ -1918,124 +1904,124 @@ nsWSRunObject::GetWSPointBefore(nsIDOMNo
     nsCOMPtr<nsIContent> textNode(do_QueryInterface(mNodeArray[curNum]));
     WSPoint point(textNode, 0, 0);
     return GetCharBefore(point);
   }
 }
 
 nsresult
 nsWSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
-{    
-  // try to change an nbsp to a space, if possible, just to prevent nbsp proliferation. 
-  // examine what is before and after the trailing nbsp, if any.
+{
+  // Try to change an nbsp to a space, if possible, just to prevent nbsp
+  // proliferation.  Examine what is before and after the trailing nbsp, if
+  // any.
   NS_ENSURE_TRUE(aRun, NS_ERROR_NULL_POINTER);
   nsresult res;
   bool leftCheck = false;
   bool spaceNBSP = false;
   bool rightCheck = false;
-  
+
   // confirm run is normalWS
   if (aRun->mType != WSType::normalWS) {
     return NS_ERROR_FAILURE;
   }
-  
+
   // first check for trailing nbsp
-  WSPoint thePoint = GetCharBefore(aRun->mEndNode, aRun->mEndOffset);
+  WSPoint thePoint = GetCharBefore(GetAsDOMNode(aRun->mEndNode), aRun->mEndOffset);
   if (thePoint.mTextNode && thePoint.mChar == nbsp) {
     // now check that what is to the left of it is compatible with replacing nbsp with space
     WSPoint prevPoint = GetCharBefore(thePoint);
     if (prevPoint.mTextNode) {
-      if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) leftCheck = true;
-      else spaceNBSP = true;
-    } else if (aRun->mLeftType == WSType::text) {
-      leftCheck = true;
-    } else if (aRun->mLeftType == WSType::special) {
+      if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) {
+        leftCheck = true;
+      } else {
+        spaceNBSP = true;
+      }
+    } else if (aRun->mLeftType == WSType::text ||
+               aRun->mLeftType == WSType::special) {
       leftCheck = true;
     }
-    if (leftCheck || spaceNBSP)
-    {
-      // now check that what is to the right of it is compatible with replacing nbsp with space
-      if (aRun->mRightType == WSType::text) {
-        rightCheck = true;
-      }
-      if (aRun->mRightType == WSType::special) {
-        rightCheck = true;
-      }
-      if (aRun->mRightType == WSType::br) {
+    if (leftCheck || spaceNBSP) {
+      // now check that what is to the right of it is compatible with replacing
+      // nbsp with space
+      if (aRun->mRightType == WSType::text ||
+          aRun->mRightType == WSType::special ||
+          aRun->mRightType == WSType::br) {
         rightCheck = true;
       }
       if ((aRun->mRightType & WSType::block) &&
-          IsBlockNode(nsCOMPtr<nsIDOMNode>(GetWSBoundingParent()))) {
-        // we are at a block boundary.  Insert a <br>.  Why?  Well, first note that
-        // the br will have no visible effect since it is up against a block boundary.
-        // |foo<br><p>bar|  renders like |foo<p>bar| and similarly
-        // |<p>foo<br></p>bar| renders like |<p>foo</p>bar|.  What this <br> addition
-        // gets us is the ability to convert a trailing nbsp to a space.  Consider:
-        // |<body>foo. '</body>|, where ' represents selection.  User types space attempting
-        // to put 2 spaces after the end of their sentence.  We used to do this as:
-        // |<body>foo. &nbsp</body>|  This caused problems with soft wrapping: the nbsp
-        // would wrap to the next line, which looked attrocious.  If you try to do:
-        // |<body>foo.&nbsp </body>| instead, the trailing space is invisible because it 
-        // is against a block boundary.  If you do: |<body>foo.&nbsp&nbsp</body>| then
-        // you get an even uglier soft wrapping problem, where foo is on one line until
-        // you type the final space, and then "foo  " jumps down to the next line.  Ugh.
-        // The best way I can find out of this is to throw in a harmless <br>
-        // here, which allows us to do: |<body>foo.&nbsp <br></body>|, which doesn't
-        // cause foo to jump lines, doesn't cause spaces to show up at the beginning of 
-        // soft wrapped lines, and lets the user see 2 spaces when they type 2 spaces.
+          IsBlockNode(nsCOMPtr<nsINode>(GetWSBoundingParent()))) {
+        // We are at a block boundary.  Insert a <br>.  Why?  Well, first note
+        // that the br will have no visible effect since it is up against a
+        // block boundary.  |foo<br><p>bar| renders like |foo<p>bar| and
+        // similarly |<p>foo<br></p>bar| renders like |<p>foo</p>bar|.  What
+        // this <br> addition gets us is the ability to convert a trailing nbsp
+        // to a space.  Consider: |<body>foo. '</body>|, where ' represents
+        // selection.  User types space attempting to put 2 spaces after the
+        // end of their sentence.  We used to do this as: |<body>foo.
+        // &nbsp</body>|  This caused problems with soft wrapping: the nbsp
+        // would wrap to the next line, which looked attrocious.  If you try to
+        // do: |<body>foo.&nbsp </body>| instead, the trailing space is
+        // invisible because it is against a block boundary.  If you do:
+        // |<body>foo.&nbsp&nbsp</body>| then you get an even uglier soft
+        // wrapping problem, where foo is on one line until you type the final
+        // space, and then "foo  " jumps down to the next line.  Ugh.  The best
+        // way I can find out of this is to throw in a harmless <br> here,
+        // which allows us to do: |<body>foo.&nbsp <br></body>|, which doesn't
+        // cause foo to jump lines, doesn't cause spaces to show up at the
+        // beginning of soft wrapped lines, and lets the user see 2 spaces when
+        // they type 2 spaces.
 
-        nsCOMPtr<nsIDOMNode> brNode;
-        res = mHTMLEditor->CreateBR(aRun->mEndNode, aRun->mEndOffset, address_of(brNode));
-        NS_ENSURE_SUCCESS(res, res);
+        nsCOMPtr<Element> brNode =
+          mHTMLEditor->CreateBR(aRun->mEndNode, aRun->mEndOffset);
+        NS_ENSURE_TRUE(brNode, NS_ERROR_FAILURE);
 
-        // refresh thePoint, prevPoint
-        thePoint = GetCharBefore(aRun->mEndNode, aRun->mEndOffset);
+        // Refresh thePoint, prevPoint
+        thePoint = GetCharBefore(GetAsDOMNode(aRun->mEndNode), aRun->mEndOffset);
         prevPoint = GetCharBefore(thePoint);
         rightCheck = true;
       }
     }
-    if (leftCheck && rightCheck)
-    {
-      // now replace nbsp with space
-      // first, insert a space
-      nsCOMPtr<nsIDOMCharacterData> textNode(do_QueryInterface(thePoint.mTextNode));
-      NS_ENSURE_TRUE(textNode, NS_ERROR_NULL_POINTER);
+    if (leftCheck && rightCheck) {
+      // Now replace nbsp with space.  First, insert a space
       nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
       nsAutoString spaceStr(char16_t(32));
-      res = mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, textNode, thePoint.mOffset, true);
+      res = mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr,
+                                                    thePoint.mTextNode,
+                                                    thePoint.mOffset, true);
       NS_ENSURE_SUCCESS(res, res);
-  
-      // finally, delete that nbsp
-      nsCOMPtr<nsIDOMNode> delNode(do_QueryInterface(thePoint.mTextNode));
-      res = DeleteChars(delNode, thePoint.mOffset+1, delNode, thePoint.mOffset+2);
+
+      // Finally, delete that nbsp
+      res = DeleteChars(GetAsDOMNode(thePoint.mTextNode), thePoint.mOffset + 1,
+                        GetAsDOMNode(thePoint.mTextNode), thePoint.mOffset + 2);
       NS_ENSURE_SUCCESS(res, res);
-    }
-    else if (!mPRE && spaceNBSP && rightCheck)  // don't mess with this preformatted for now.
-    {
-      // we have a run of ascii whitespace (which will render as one space)
-      // followed by an nbsp (which is at the end of the whitespace run).  Let's
-      // switch their order.  This will insure that if someone types two spaces
-      // after a sentence, and the editor softwraps at this point, the spaces wont
-      // be split across lines, which looks ugly and is bad for the moose.
-      
-      nsCOMPtr<nsIDOMNode> startNode, endNode, thenode(do_QueryInterface(prevPoint.mTextNode));
+    } else if (!mPRE && spaceNBSP && rightCheck) {
+      // Don't mess with this preformatted for now.  We have a run of ASCII
+      // whitespace (which will render as one space) followed by an nbsp (which
+      // is at the end of the whitespace run).  Let's switch their order.  This
+      // will ensure that if someone types two spaces after a sentence, and the
+      // editor softwraps at this point, the spaces won't be split across lines,
+      // which looks ugly and is bad for the moose.
+
+      nsCOMPtr<Text> startNode, endNode;
       int32_t startOffset, endOffset;
-      GetAsciiWSBounds(eBoth, thenode, prevPoint.mOffset+1, address_of(startNode),
-                       &startOffset, address_of(endNode), &endOffset);
-      
-      //  delete that nbsp
-      nsCOMPtr<nsIDOMNode> delNode(do_QueryInterface(thePoint.mTextNode));
-      res = DeleteChars(delNode, thePoint.mOffset, delNode, thePoint.mOffset+1);
+      GetAsciiWSBounds(eBoth, prevPoint.mTextNode, prevPoint.mOffset + 1,
+                       getter_AddRefs(startNode), &startOffset,
+                       getter_AddRefs(endNode), &endOffset);
+
+      // Delete that nbsp
+      res = DeleteChars(GetAsDOMNode(thePoint.mTextNode), thePoint.mOffset,
+                        GetAsDOMNode(thePoint.mTextNode), thePoint.mOffset + 1);
       NS_ENSURE_SUCCESS(res, res);
-      
-      // finally, insert that nbsp before the ascii ws run
+
+      // Finally, insert that nbsp before the ASCII ws run
       nsAutoTxnsConserveSelection dontSpazMySelection(mHTMLEditor);
       nsAutoString nbspStr(nbsp);
-      nsCOMPtr<nsIDOMCharacterData> textNode(do_QueryInterface(startNode));
-      res = mHTMLEditor->InsertTextIntoTextNodeImpl(nbspStr, textNode, startOffset, true);
+      res = mHTMLEditor->InsertTextIntoTextNodeImpl(nbspStr, startNode,
+                                                    startOffset, true);
       NS_ENSURE_SUCCESS(res, res);
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsWSRunObject::CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, int32_t aOffset)
@@ -2117,39 +2103,21 @@ nsWSRunObject::CheckLeadingNBSP(WSFragme
     res = DeleteChars(delNode, thePoint.mOffset+1, delNode, thePoint.mOffset+2);
     NS_ENSURE_SUCCESS(res, res);
   }
   return NS_OK;
 }
 
 
 nsresult
-nsWSRunObject::ScrubBlockBoundaryInner(nsHTMLEditor *aHTMLEd, 
-                                       nsCOMPtr<nsIDOMNode> *aBlock,
-                                       BlockBoundary aBoundary)
-{
-  NS_ENSURE_TRUE(aBlock && aHTMLEd, NS_ERROR_NULL_POINTER);
-  int32_t offset=0;
-  if (aBoundary == kBlockEnd)
-  {
-    uint32_t uOffset;
-    aHTMLEd->GetLengthOfDOMNode(*aBlock, uOffset); 
-    offset = uOffset;
-  }
-  nsWSRunObject theWSObj(aHTMLEd, *aBlock, offset);
-  return theWSObj.Scrub();    
-}
-
-
-nsresult
 nsWSRunObject::Scrub()
 {
   WSFragment *run = mStartRun;
   while (run)
   {
     if (run->mType & (WSType::leadingWS | WSType::trailingWS)) {
-      nsresult res = DeleteChars(run->mStartNode, run->mStartOffset, run->mEndNode, run->mEndOffset);
+      nsresult res = DeleteChars(GetAsDOMNode(run->mStartNode), run->mStartOffset, GetAsDOMNode(run->mEndNode), run->mEndOffset);
       NS_ENSURE_SUCCESS(res, res);
     }
     run = run->mRight;
   }
   return NS_OK;
 }
--- a/editor/libeditor/html/nsWSRunObject.h
+++ b/editor/libeditor/html/nsWSRunObject.h
@@ -3,21 +3,21 @@
  * 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 __wsrunobject_h__
 #define __wsrunobject_h__
 
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
-#include "nsIContent.h"
 #include "nsIDOMNode.h"
 #include "nsIEditor.h"
 #include "nsINode.h"
 #include "nscore.h"
+#include "mozilla/dom/Text.h"
 
 class nsHTMLEditor;
 class nsIDOMDocument;
 class nsIDOMNode;
 struct DOMPoint;
 
 // class nsWSRunObject represents the entire whitespace situation
 // around a given point.  It collects up a list of nodes that contain
@@ -148,42 +148,48 @@ class MOZ_STACK_CLASS nsWSRunObject
       kAfterBlock
     };
 
     enum {eBefore = 1};
     enum {eAfter  = 1 << 1};
     enum {eBoth   = eBefore | eAfter};
 
     // constructor / destructor -----------------------------------------------
+    nsWSRunObject(nsHTMLEditor* aEd, nsINode* aNode, int32_t aOffset);
     nsWSRunObject(nsHTMLEditor *aEd, nsIDOMNode *aNode, int32_t aOffset);
     ~nsWSRunObject();
     
     // public methods ---------------------------------------------------------
 
     // ScrubBlockBoundary removes any non-visible whitespace at the specified
     // location relative to a block node.  
-    static nsresult ScrubBlockBoundary(nsHTMLEditor *aHTMLEd, 
-                                       nsCOMPtr<nsIDOMNode> *aBlock,
+    static nsresult ScrubBlockBoundary(nsHTMLEditor* aHTMLEd,
                                        BlockBoundary aBoundary,
-                                       int32_t *aOffset = 0);
+                                       nsINode* aBlock,
+                                       int32_t aOffset = -1);
     
     // PrepareToJoinBlocks fixes up ws at the end of aLeftParent and the
     // beginning of aRightParent in preperation for them to be joined.
     // example of fixup: trailingws in aLeftParent needs to be removed.
     static nsresult PrepareToJoinBlocks(nsHTMLEditor *aEd, 
                                         nsIDOMNode *aLeftParent,
                                         nsIDOMNode *aRightParent);
 
     // PrepareToDeleteRange fixes up ws before {aStartNode,aStartOffset}
     // and after {aEndNode,aEndOffset} in preperation for content
     // in that range to be deleted.  Note that the nodes and offsets
     // are adjusted in response to any dom changes we make while 
     // adjusting ws.
     // example of fixup: trailingws before {aStartNode,aStartOffset}
     //                   needs to be removed.
+    static nsresult PrepareToDeleteRange(nsHTMLEditor* aHTMLEd,
+                                         nsCOMPtr<nsINode>* aStartNode,
+                                         int32_t* aStartOffset,
+                                         nsCOMPtr<nsINode>* aEndNode,
+                                         int32_t* aEndOffset);
     static nsresult PrepareToDeleteRange(nsHTMLEditor *aHTMLEd, 
                                          nsCOMPtr<nsIDOMNode> *aStartNode,
                                          int32_t *aStartOffset, 
                                          nsCOMPtr<nsIDOMNode> *aEndNode,
                                          int32_t *aEndOffset);
 
     // PrepareToDeleteNode fixes up ws before and after aNode in preperation 
     // for aNode to be deleted.
@@ -201,20 +207,19 @@ class MOZ_STACK_CLASS nsWSRunObject
     static nsresult PrepareToSplitAcrossBlocks(nsHTMLEditor *aHTMLEd, 
                                                nsCOMPtr<nsIDOMNode> *aSplitNode, 
                                                int32_t *aSplitOffset);
 
     // InsertBreak inserts a br node at {aInOutParent,aInOutOffset}
     // and makes any needed adjustments to ws around that point.
     // example of fixup: normalws after {aInOutParent,aInOutOffset}
     //                   needs to begin with nbsp.
-    nsresult InsertBreak(nsCOMPtr<nsIDOMNode> *aInOutParent, 
-                         int32_t *aInOutOffset, 
-                         nsCOMPtr<nsIDOMNode> *outBRNode, 
-                         nsIEditor::EDirection aSelect);
+    already_AddRefed<mozilla::dom::Element>
+      InsertBreak(nsCOMPtr<nsINode>* aInOutParent, int32_t* aInOutOffset,
+                  nsIEditor::EDirection aSelect);
 
     // InsertText inserts a string at {aInOutParent,aInOutOffset}
     // and makes any needed adjustments to ws around that point.
     // example of fixup: trailingws before {aInOutParent,aInOutOffset}
     //                   needs to be removed.
     nsresult InsertText(const nsAString& aStringToInsert, 
                         nsCOMPtr<nsIDOMNode> *aInOutNode, 
                         int32_t *aInOutOffset,
@@ -261,20 +266,20 @@ class MOZ_STACK_CLASS nsWSRunObject
   protected:
     
     // WSFragment struct ---------------------------------------------------------
     // WSFragment represents a single run of ws (all leadingws, or all normalws,
     // or all trailingws, or all leading+trailingws).  Note that this single run may
     // still span multiple nodes.
     struct WSFragment
     {
-      nsCOMPtr<nsIDOMNode> mStartNode;  // node where ws run starts
-      nsCOMPtr<nsIDOMNode> mEndNode;    // node where ws run ends
-      int32_t mStartOffset;             // offset where ws run starts
-      int32_t mEndOffset;               // offset where ws run ends
+      nsCOMPtr<nsINode> mStartNode;  // node where ws run starts
+      nsCOMPtr<nsINode> mEndNode;    // node where ws run ends
+      int32_t mStartOffset;          // offset where ws run starts
+      int32_t mEndOffset;            // offset where ws run ends
       // type of ws, and what is to left and right of it
       WSType mType, mLeftType, mRightType;
       // other ws runs to left or right.  may be null.
       WSFragment *mLeft, *mRight;
 
       WSFragment() : mStartNode(0), mEndNode(0),
                      mStartOffset(0), mEndOffset(0),
                      mType(), mLeftType(), mRightType(),
@@ -285,130 +290,118 @@ class MOZ_STACK_CLASS nsWSRunObject
     
     // WSPoint struct ------------------------------------------------------------
     // A WSPoint struct represents a unique location within the ws run.  It is 
     // always within a textnode that is one of the nodes stored in the list
     // in the wsRunObject.  For convenience, the character at that point is also 
     // stored in the struct.
     struct MOZ_STACK_CLASS WSPoint
     {
-      nsCOMPtr<nsIContent> mTextNode;
+      nsCOMPtr<mozilla::dom::Text> mTextNode;
       uint32_t mOffset;
       char16_t mChar;
 
       WSPoint() : mTextNode(0),mOffset(0),mChar(0) {}
-      WSPoint(nsIDOMNode *aNode, int32_t aOffset, char16_t aChar) : 
+      WSPoint(nsINode* aNode, int32_t aOffset, char16_t aChar) :
                      mTextNode(do_QueryInterface(aNode)),mOffset(aOffset),mChar(aChar)
       {
-        if (!mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) {
-          // Not sure if this is needed, but it'll maintain the same
-          // functionality
-          mTextNode = nullptr;
-        }
+        MOZ_ASSERT(mTextNode->IsNodeOfType(nsINode::eTEXT));
       }
-      WSPoint(nsIContent *aTextNode, int32_t aOffset, char16_t aChar) : 
+      WSPoint(mozilla::dom::Text* aTextNode, int32_t aOffset, char16_t aChar) :
                      mTextNode(aTextNode),mOffset(aOffset),mChar(aChar) {}
     };    
 
     enum AreaRestriction
     {
       eAnywhere, eOutsideUserSelectAll
     };    
     
     // protected methods ---------------------------------------------------------
     // tons of utility methods.  
 
     /**
      * Return the node which we will handle white-space under. This is the
      * closest block within the DOM subtree we're editing, or if none is
      * found, the (inline) root of the editable subtree.
      */
-    already_AddRefed<nsIDOMNode> GetWSBoundingParent();
+    already_AddRefed<nsINode> GetWSBoundingParent();
 
     nsresult GetWSNodes();
     void     GetRuns();
     void     ClearRuns();
     void     MakeSingleWSRun(WSType aType);
-    nsresult PrependNodeToList(nsIDOMNode *aNode);
-    nsresult AppendNodeToList(nsIDOMNode *aNode);
-    nsresult GetPreviousWSNode(nsIDOMNode *aStartNode, 
-                               nsIDOMNode *aBlockParent, 
-                               nsCOMPtr<nsIDOMNode> *aPriorNode);
-    nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
-                               int32_t      aOffset,
-                               nsIDOMNode  *aBlockParent, 
-                               nsCOMPtr<nsIDOMNode> *aPriorNode);
+    nsresult PrependNodeToList(nsINode* aNode);
+    nsresult AppendNodeToList(nsINode* aNode);
     nsresult GetPreviousWSNode(::DOMPoint aPoint,
-                               nsIDOMNode  *aBlockParent, 
-                               nsCOMPtr<nsIDOMNode> *aPriorNode);
-    nsresult GetNextWSNode(nsIDOMNode *aStartNode, 
-                           nsIDOMNode *aBlockParent, 
-                           nsCOMPtr<nsIDOMNode> *aNextNode);
-    nsresult GetNextWSNode(nsIDOMNode *aStartNode,
-                           int32_t     aOffset,
-                           nsIDOMNode *aBlockParent, 
-                           nsCOMPtr<nsIDOMNode> *aNextNode);
+                               nsINode* aBlockParent,
+                               nsCOMPtr<nsINode>* aPriorNode);
     nsresult GetNextWSNode(::DOMPoint aPoint,
-                           nsIDOMNode  *aBlockParent, 
-                           nsCOMPtr<nsIDOMNode> *aNextNode);
+                           nsINode* aBlockParent,
+                           nsCOMPtr<nsINode>* aNextNode);
     nsresult PrepareToDeleteRangePriv(nsWSRunObject* aEndObject);
     nsresult PrepareToSplitAcrossBlocksPriv();
     nsresult DeleteChars(nsIDOMNode *aStartNode, int32_t aStartOffset, 
                          nsIDOMNode *aEndNode, int32_t aEndOffset,
                          AreaRestriction aAR = eAnywhere);
     WSPoint  GetCharAfter(nsIDOMNode *aNode, int32_t aOffset);
     WSPoint  GetCharBefore(nsIDOMNode *aNode, int32_t aOffset);
     WSPoint  GetCharAfter(const WSPoint &aPoint);
     WSPoint  GetCharBefore(const WSPoint &aPoint);
     nsresult ConvertToNBSP(WSPoint aPoint,
                            AreaRestriction aAR = eAnywhere);
+    void     GetAsciiWSBounds(int16_t aDir, nsINode* aNode, int32_t aOffset,
+                              mozilla::dom::Text** outStartNode,
+                              int32_t* outStartOffset,
+                              mozilla::dom::Text** outEndNode,
+                              int32_t* outEndOffset);
     void     GetAsciiWSBounds(int16_t aDir, nsIDOMNode *aNode, int32_t aOffset,
                                 nsCOMPtr<nsIDOMNode> *outStartNode, int32_t *outStartOffset,
                                 nsCOMPtr<nsIDOMNode> *outEndNode, int32_t *outEndOffset);
     void     FindRun(nsIDOMNode *aNode, int32_t aOffset, WSFragment **outRun, bool after);
     char16_t GetCharAt(nsIContent *aTextNode, int32_t aOffset);
     WSPoint  GetWSPointAfter(nsIDOMNode *aNode, int32_t aOffset);
     WSPoint  GetWSPointBefore(nsIDOMNode *aNode, int32_t aOffset);
     nsresult CheckTrailingNBSPOfRun(WSFragment *aRun);
     nsresult CheckTrailingNBSP(WSFragment *aRun, nsIDOMNode *aNode, int32_t aOffset);
     nsresult CheckLeadingNBSP(WSFragment *aRun, nsIDOMNode *aNode, int32_t aOffset);
     
-    static nsresult ScrubBlockBoundaryInner(nsHTMLEditor *aHTMLEd, 
-                                       nsCOMPtr<nsIDOMNode> *aBlock,
-                                       BlockBoundary aBoundary);
     nsresult Scrub();
+    nsresult GetPreviousWSNodeInner(nsINode* aStartNode, nsINode* aBlockParent,
+                                    nsCOMPtr<nsINode>* aPriorNode);
+    nsresult GetNextWSNodeInner(nsINode* aStartNode, nsINode* aBlockParent,
+                                nsCOMPtr<nsINode>* aNextNode);
     
     // member variables ---------------------------------------------------------
     
-    nsCOMPtr<nsIDOMNode> mNode;           // the node passed to our constructor
-    int32_t mOffset;                      // the offset passed to our contructor
+    nsCOMPtr<nsINode> mNode;           // the node passed to our constructor
+    int32_t mOffset;                   // the offset passed to our contructor
     // together, the above represent the point at which we are building up ws info.
     
-    bool    mPRE;                         // true if we are in preformatted whitespace context
-    nsCOMPtr<nsIDOMNode> mStartNode;      // node/offset where ws starts
-    int32_t mStartOffset;                 // ...
-    WSType mStartReason;                  // reason why ws starts (eText, eOtherBlock, etc)
-    nsCOMPtr<nsIDOMNode> mStartReasonNode;// the node that implicated by start reason
+    bool    mPRE;                      // true if we are in preformatted whitespace context
+    nsCOMPtr<nsINode> mStartNode;      // node/offset where ws starts
+    int32_t mStartOffset;              // ...
+    WSType mStartReason;               // reason why ws starts (eText, eOtherBlock, etc)
+    nsCOMPtr<nsINode> mStartReasonNode;// the node that implicated by start reason
     
-    nsCOMPtr<nsIDOMNode> mEndNode;        // node/offset where ws ends
-    int32_t mEndOffset;                   // ...
-    WSType mEndReason;                    // reason why ws ends (eText, eOtherBlock, etc)
-    nsCOMPtr<nsIDOMNode> mEndReasonNode;  // the node that implicated by end reason
+    nsCOMPtr<nsINode> mEndNode;        // node/offset where ws ends
+    int32_t mEndOffset;                // ...
+    WSType mEndReason;                 // reason why ws ends (eText, eOtherBlock, etc)
+    nsCOMPtr<nsINode> mEndReasonNode;  // the node that implicated by end reason
     
-    nsCOMPtr<nsIDOMNode> mFirstNBSPNode;  // location of first nbsp in ws run, if any
-    int32_t mFirstNBSPOffset;             // ...
+    nsCOMPtr<nsINode> mFirstNBSPNode;  // location of first nbsp in ws run, if any
+    int32_t mFirstNBSPOffset;          // ...
     
-    nsCOMPtr<nsIDOMNode> mLastNBSPNode;   // location of last nbsp in ws run, if any
-    int32_t mLastNBSPOffset;              // ...
+    nsCOMPtr<nsINode> mLastNBSPNode;   // location of last nbsp in ws run, if any
+    int32_t mLastNBSPOffset;           // ...
     
-    nsCOMArray<nsIDOMNode> mNodeArray;//the list of nodes containing ws in this run
+    nsCOMArray<nsINode> mNodeArray;    //the list of nodes containing ws in this run
     
-    WSFragment *mStartRun;                // the first WSFragment in the run
-    WSFragment *mEndRun;                  // the last WSFragment in the run, may be same as first
+    WSFragment *mStartRun;             // the first WSFragment in the run
+    WSFragment *mEndRun;               // the last WSFragment in the run, may be same as first
     
-    nsHTMLEditor *mHTMLEditor;            // non-owning.
+    nsHTMLEditor *mHTMLEditor;         // non-owning.
     
     friend class nsHTMLEditRules;  // opening this class up for pillaging
     friend class nsHTMLEditor;     // opening this class up for more pillaging
 };
 
 #endif
 
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -433,16 +433,30 @@ nsPlaintextEditor::TypedText(const nsASt
     case eTypedBreak:
       return InsertLineBreak();
     default:
       // eTypedBR is only for HTML
       return NS_ERROR_FAILURE;
   }
 }
 
+already_AddRefed<Element>
+nsPlaintextEditor::CreateBRImpl(nsCOMPtr<nsINode>* aInOutParent,
+                                int32_t* aInOutOffset,
+                                EDirection aSelect)
+{
+  nsCOMPtr<nsIDOMNode> parent(GetAsDOMNode(*aInOutParent));
+  nsCOMPtr<nsIDOMNode> br;
+  // We ignore the retval, and assume it's fine if the br is non-null
+  CreateBRImpl(address_of(parent), aInOutOffset, address_of(br), aSelect);
+  *aInOutParent = do_QueryInterface(parent);
+  nsCOMPtr<Element> ret(do_QueryInterface(br));
+  return ret.forget();
+}
+
 nsresult
 nsPlaintextEditor::CreateBRImpl(nsCOMPtr<nsIDOMNode>* aInOutParent,
                                 int32_t* aInOutOffset,
                                 nsCOMPtr<nsIDOMNode>* outBRNode,
                                 EDirection aSelect)
 {
   NS_ENSURE_TRUE(aInOutParent && *aInOutParent && aInOutOffset && outBRNode, NS_ERROR_NULL_POINTER);
   *outBRNode = nullptr;
--- a/editor/libeditor/text/nsPlaintextEditor.h
+++ b/editor/libeditor/text/nsPlaintextEditor.h
@@ -171,16 +171,19 @@ protected:
   NS_IMETHOD GetAndInitDocEncoder(const nsAString& aFormatType,
                                   uint32_t aFlags,
                                   const nsACString& aCharset,
                                   nsIDocumentEncoder** encoder);
 
   // key event helpers
   NS_IMETHOD CreateBR(nsIDOMNode *aNode, int32_t aOffset, 
                       nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect = eNone);
+  already_AddRefed<mozilla::dom::Element>
+      CreateBRImpl(nsCOMPtr<nsINode>* aInOutParent, int32_t* aInOutOffset,
+                   EDirection aSelect);
   nsresult CreateBRImpl(nsCOMPtr<nsIDOMNode>* aInOutParent,
                         int32_t* aInOutOffset,
                         nsCOMPtr<nsIDOMNode>* outBRNode,
                         EDirection aSelect);
   nsresult InsertBR(nsCOMPtr<nsIDOMNode>* outBRNode);
 
   // factored methods for handling insertion of data from transferables (drag&drop or clipboard)
   NS_IMETHOD PrepareTransferable(nsITransferable **transferable);
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -1153,31 +1153,32 @@ nsTextEditRules::CreateBogusNodeIfNeeded
   }
 
   // Skip adding the bogus node if body is read-only.
   if (!mEditor->IsModifiableNode(body)) {
     return NS_OK;
   }
 
   // Create a br.
-  nsCOMPtr<dom::Element> newContent;
-  nsresult rv = mEditor->CreateHTMLContent(NS_LITERAL_STRING("br"), getter_AddRefs(newContent));
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult res;
+  nsCOMPtr<Element> newContent =
+    mEditor->CreateHTMLContent(NS_LITERAL_STRING("br"), res);
+  NS_ENSURE_SUCCESS(res.ErrorCode(), res.ErrorCode());
 
   // set mBogusNode to be the newly created <br>
   mBogusNode = do_QueryInterface(newContent);
   NS_ENSURE_TRUE(mBogusNode, NS_ERROR_NULL_POINTER);
 
   // Give it a special attribute.
   newContent->SetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
                       kMOZEditorBogusNodeValue, false);
 
   // Put the node in the document.
   nsCOMPtr<nsIDOMNode> bodyNode = do_QueryInterface(body);
-  rv = mEditor->InsertNode(mBogusNode, bodyNode, 0);
+  nsresult rv = mEditor->InsertNode(mBogusNode, bodyNode, 0);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Set selection.
   aSelection->CollapseNative(body, 0);
   return NS_OK;
 }
 
 
--- a/editor/libeditor/text/nsTextEditUtils.cpp
+++ b/editor/libeditor/text/nsTextEditUtils.cpp
@@ -33,16 +33,23 @@ nsTextEditUtils::IsBody(nsIDOMNode *node
 
 ///////////////////////////////////////////////////////////////////////////
 // IsBreak: true if node an html break node
 bool 
 nsTextEditUtils::IsBreak(nsIDOMNode *node)
 {
   return nsEditor::NodeIsType(node, nsGkAtoms::br);
 }
+ 
+bool 
+nsTextEditUtils::IsBreak(nsINode* aNode)
+{
+  MOZ_ASSERT(aNode);
+  return aNode->IsElement() && aNode->AsElement()->IsHTML(nsGkAtoms::br);
+}
 
 
 ///////////////////////////////////////////////////////////////////////////
 // IsMozBR: true if node an html br node with type = _moz
 //                  
 bool 
 nsTextEditUtils::IsMozBR(nsIDOMNode *node)
 {
--- a/editor/libeditor/text/nsTextEditUtils.h
+++ b/editor/libeditor/text/nsTextEditUtils.h
@@ -18,16 +18,17 @@ class nsIDOMNode;
 class nsPlaintextEditor;
 
 class nsTextEditUtils
 {
 public:
   // from nsTextEditRules:
   static bool IsBody(nsIDOMNode* aNode);
   static bool IsBreak(nsIDOMNode* aNode);
+  static bool IsBreak(nsINode* aNode);
   static bool IsMozBR(nsIDOMNode* aNode);
   static bool IsMozBR(nsINode* aNode);
   static bool HasMozAttr(nsIDOMNode* aNode);
 };
 
 /***************************************************************************
  * stack based helper class for detecting end of editor initialization, in
  * order to trigger "end of init" initialization of the edit rules.
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -608,30 +608,40 @@ CairoImage::CairoImage()
 
 CairoImage::~CairoImage()
 {
 }
 
 TextureClient*
 CairoImage::GetTextureClient(CompositableClient *aClient)
 {
+  if (!aClient) {
+    return nullptr;
+  }
+
   CompositableForwarder* forwarder = aClient->GetForwarder();
   RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial());
   if (textureClient) {
     return textureClient;
   }
 
   RefPtr<SourceSurface> surface = GetAsSourceSurface();
   MOZ_ASSERT(surface);
+  if (!surface) {
+    return nullptr;
+  }
 
   // gfx::BackendType::NONE means default to content backend
   textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
                                                          TextureFlags::DEFAULT,
                                                          gfx::BackendType::NONE,
                                                          surface->GetSize());
+  if (!textureClient) {
+    return nullptr;
+  }
   MOZ_ASSERT(textureClient->CanExposeDrawTarget());
   if (!textureClient->AllocateForSurface(surface->GetSize()) ||
       !textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
     return nullptr;
   }
 
   {
     // We must not keep a reference to the DrawTarget after it has been unlocked.
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -324,23 +324,24 @@ APZCCallbackHelper::GetDOMWindowUtils(co
     nsIDocument* doc = aContent->GetCurrentDoc();
     if (doc) {
         utils = GetDOMWindowUtils(doc);
     }
     return utils.forget();
 }
 
 bool
-APZCCallbackHelper::GetScrollIdentifiers(const nsIContent* aContent,
-                                         uint32_t* aPresShellIdOut,
-                                         FrameMetrics::ViewID* aViewIdOut)
+APZCCallbackHelper::GetOrCreateScrollIdentifiers(nsIContent* aContent,
+                                                 uint32_t* aPresShellIdOut,
+                                                 FrameMetrics::ViewID* aViewIdOut)
 {
-    if (!aContent || !nsLayoutUtils::FindIDFor(aContent, aViewIdOut)) {
+    if (!aContent) {
         return false;
     }
+    *aViewIdOut = nsLayoutUtils::FindOrCreateIDFor(aContent);
     nsCOMPtr<nsIDOMWindowUtils> utils = GetDOMWindowUtils(aContent);
     return utils && (utils->GetPresShellId(aPresShellIdOut) == NS_OK);
 }
 
 class AcknowledgeScrollUpdateEvent : public nsRunnable
 {
     typedef mozilla::layers::FrameMetrics::ViewID ViewID;
 
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -53,21 +53,23 @@ public:
 
     /* Get the DOMWindowUtils for the window corresponding to the given document. */
     static already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils(const nsIDocument* aDoc);
 
     /* Get the DOMWindowUtils for the window corresponding to the givent content
        element. This might be an iframe inside the tab, for instance. */
     static already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils(const nsIContent* aContent);
 
-    /* Get the presShellId and view ID for the given content element, if they can be
-       found. Returns false if the values could not be found, true if they could. */
-    static bool GetScrollIdentifiers(const nsIContent* aContent,
-                                     uint32_t* aPresShellIdOut,
-                                     FrameMetrics::ViewID* aViewIdOut);
+    /* Get the presShellId and view ID for the given content element.
+     * If the view ID does not exist, one is created.
+     * The pres shell ID should generally already exist; if it doesn't for some
+     * reason, false is returned. */
+    static bool GetOrCreateScrollIdentifiers(nsIContent* aContent,
+                                             uint32_t* aPresShellIdOut,
+                                             FrameMetrics::ViewID* aViewIdOut);
 
     /* Tell layout that we received the scroll offset update for the given view ID, so
        that it accepts future scroll offset updates from APZ. */
     static void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
                                         const uint32_t& aScrollGeneration);
 
     /* Save an "input transform" property on the content element corresponding to
        the scrollable content. This is needed because in some cases when the APZ code
--- a/image/test/mochitest/mochitest.ini
+++ b/image/test/mochitest/mochitest.ini
@@ -54,17 +54,16 @@ support-files =
   source.png
   over.png
   6M-pixels.png
   12M-pixels-1.png
   12M-pixels-2.png
 
 [test_ImageContentLoaded.html]
 [test_bug399925.html]
-skip-if = e10s || buildapp == 'b2g' #Bug 969779 - should set preference via SpecialPowers.pushPrefEnv()
 # [test_bug435296.html]
 # disabled - See bug 578591
 [test_bug466586.html]
 [test_bug468160.html]
 # [test_bug478398.html]
 # disabled - See bug 579139
 [test_bug490949.html]
 [test_bug496292.html]
--- a/image/test/mochitest/test_bug399925.html
+++ b/image/test/mochitest/test_bug399925.html
@@ -8,73 +8,77 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="imgutils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=399925">Mozilla Bug 399925</a>
 <p id="display"></p>
 <div id="content" style="display: none">
-<img src="bug399925.gif" id="gif" />
 <canvas id="canvas" width="100" height="100"> </canvas>  
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 399925. **/
 var pngResults = new Array();
-var oldTimeoutPref;
-var oldDiscardPref;
 SimpleTest.waitForExplicitFinish();
-window.onload = runTest;
-
-function runTest()
-{
-  // Get the old discard timeout
-  oldTimeoutPref = getImagePref(DISCARD_TIMEOUT_PREF);
 
-  // We're testing discarding here, so we should make sure it's flipped on
-  oldDiscardPref = getImagePref(DISCARD_ENABLED_PREF);
+window.onload = function() {
+  // 1. Enable Discarding
+  // 2. Sets the discard timer to 500ms so we don't have to wait so long. The
+  //    actual time is nondeterministic, but is bounded by 2 * timer = 1 second.
+  SpecialPowers.pushPrefEnv({
+    'set':[['image.mem.discardable',true],
+           ['image.mem.min_discard_timeout_ms',1000]]
+  }, runTest);
+}
 
-  // Enable Discarding
-  setImagePref(DISCARD_ENABLED_PREF, true);
-
-  // Sets the discard timer to 500ms so we don't have to wait so long. The
-  // actual time is nondeterministic, but is bounded by 2 * timer = 1 second.
-  setImagePref(DISCARD_TIMEOUT_PREF, 1000);
-
+function runTest() {
   // Create the image _after_ setting the discard timer pref
   var image = new Image();
   image.setAttribute("id", "gif");
   image.src = "bug399925.gif";
   document.getElementById("content").appendChild(image);
 
-  // draw the canvas once
-  drawCanvas();
-
-  // Set the timeout to draw it after discard
-  setTimeout('drawCanvas(); allDone();', 3000);
+  // 1. Draw the canvas once on loadComplete
+  // 2. Redraw the canvas and compare the results right on discard
+  addCallbacks(image, drawCanvas, function() {
+    drawCanvas();
+    is(pngResults[0], pngResults[1], "got different rendered results");
+    SimpleTest.finish();
+  });
 }
 
-function drawCanvas()
-{
-    var canvas = document.getElementById('canvas');
-    var context = canvas.getContext('2d');
-    var gif = document.getElementById('gif');
+function addCallbacks(anImage, loadCompleteCallback, discardCallback) {
+  var observer = new ImageDecoderObserverStub();
+  observer.discard = function () {
+    imgLoadingContent.removeObserver(scriptedObserver);
+    discardCallback();
+  }
+  observer.loadComplete = loadCompleteCallback;
+  observer = SpecialPowers.wrapCallbackObject(observer);
 
-    context.drawImage(gif, 0, 0);
-    ok(true, "we got through the drawImage call without an exception being thrown");
-    pngResults.push(canvas.toDataURL);
+  var scriptedObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
+                           .getService(SpecialPowers.Ci.imgITools)
+                           .createScriptedObserver(observer);
+
+  var imgLoadingContent =
+    SpecialPowers.wrap(anImage)
+                 .QueryInterface(SpecialPowers.Ci.nsIImageLoadingContent);
+  imgLoadingContent.addObserver(scriptedObserver);
 }
 
-function allDone()
-{
-    is(pngResults[0], pngResults[1], "got different rendered results");
-    setImagePref(DISCARD_TIMEOUT_PREF, oldTimeoutPref);
-    setImagePref(DISCARD_ENABLED_PREF, oldDiscardPref);
-    SimpleTest.finish();
+function drawCanvas() {
+  var canvas = document.getElementById('canvas');
+  var context = canvas.getContext('2d');
+  var gif = document.getElementById('gif');
+
+  context.drawImage(gif, 0, 0);
+  ok(true, "we got through the drawImage call without an exception being thrown");
+  pngResults.push(canvas.toDataURL());
 }
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -394,16 +394,26 @@ class StoreBuffer
     template <typename Buffer, typename Edge>
     void unputFromAnyThread(Buffer &buffer, const Edge &edge) {
         if (!isOkayToUseBuffer())
             return;
         mozilla::ReentrancyGuard g(*this);
         buffer.unput(this, edge);
     }
 
+    template <typename Buffer, typename Edge>
+    void putFromMainThread(Buffer &buffer, const Edge &edge) {
+        if (!isEnabled())
+            return;
+        JS_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
+        mozilla::ReentrancyGuard g(*this);
+        if (edge.maybeInRememberedSet(nursery_))
+            buffer.put(this, edge);
+    }
+
     MonoTypeBuffer<ValueEdge> bufferVal;
     MonoTypeBuffer<CellPtrEdge> bufferCell;
     MonoTypeBuffer<SlotsEdge> bufferSlot;
     MonoTypeBuffer<WholeCellEdges> bufferWholeCell;
     RelocatableMonoTypeBuffer<ValueEdge> bufferRelocVal;
     RelocatableMonoTypeBuffer<CellPtrEdge> bufferRelocCell;
     GenericBuffer bufferGeneric;
 
@@ -433,19 +443,19 @@ class StoreBuffer
     bool isAboutToOverflow() const { return aboutToOverflow_; }
 
     /* Insert a single edge into the buffer/remembered set. */
     void putValueFromAnyThread(JS::Value *valuep) { putFromAnyThread(bufferVal, ValueEdge(valuep)); }
     void putCellFromAnyThread(Cell **cellp) { putFromAnyThread(bufferCell, CellPtrEdge(cellp)); }
     void putSlotFromAnyThread(JSObject *obj, int kind, int32_t start, int32_t count) {
         putFromAnyThread(bufferSlot, SlotsEdge(obj, kind, start, count));
     }
-    void putWholeCell(Cell *cell) {
+    void putWholeCellFromMainThread(Cell *cell) {
         JS_ASSERT(cell->isTenured());
-        putFromAnyThread(bufferWholeCell, WholeCellEdges(cell));
+        putFromMainThread(bufferWholeCell, WholeCellEdges(cell));
     }
 
     /* Insert or update a single edge in the Relocatable buffer. */
     void putRelocatableValueFromAnyThread(JS::Value *valuep) {
         putFromAnyThread(bufferRelocVal, ValueEdge(valuep));
     }
     void removeRelocatableValueFromAnyThread(JS::Value *valuep) {
         unputFromAnyThread(bufferRelocVal, ValueEdge(valuep));
--- a/js/src/jit/IonLinker.h
+++ b/js/src/jit/IonLinker.h
@@ -62,17 +62,17 @@ class Linker
         if (!code)
             return nullptr;
         if (masm.oom())
             return fail(cx);
         code->copyFrom(masm);
         masm.link(code);
 #ifdef JSGC_GENERATIONAL
         if (masm.embedsNurseryPointers())
-            cx->runtime()->gc.storeBuffer.putWholeCell(code);
+            cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(code);
 #endif
         return code;
     }
 
   public:
     Linker(MacroAssembler &masm)
       : masm(masm)
     {
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -548,37 +548,37 @@ NewCallObject(JSContext *cx, HandleShape
     JSObject *obj = CallObject::create(cx, shape, type, slots);
     if (!obj)
         return nullptr;
 
 #ifdef JSGC_GENERATIONAL
     // The JIT creates call objects in the nursery, so elides barriers for
     // the initializing writes. The interpreter, however, may have allocated
     // the call object tenured, so barrier as needed before re-entering.
-    if (!IsInsideNursery(cx->runtime(), obj))
-        cx->runtime()->gc.storeBuffer.putWholeCell(obj);
+    if (!IsInsideNursery(obj))
+        cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
 #endif
 
     return obj;
 }
 
 JSObject *
 NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots)
 {
     JSObject *obj = CallObject::createSingleton(cx, shape, slots);
     if (!obj)
         return nullptr;
 
 #ifdef JSGC_GENERATIONAL
     // The JIT creates call objects in the nursery, so elides barriers for
     // the initializing writes. The interpreter, however, may have allocated
     // the call object tenured, so barrier as needed before re-entering.
-    MOZ_ASSERT(!IsInsideNursery(cx->runtime(), obj),
+    MOZ_ASSERT(!IsInsideNursery(obj),
                "singletons are created in the tenured heap");
-    cx->runtime()->gc.storeBuffer.putWholeCell(obj);
+    cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
 #endif
 
     return obj;
 }
 
 JSObject *
 NewStringObject(JSContext *cx, HandleString str)
 {
@@ -709,17 +709,17 @@ FilterArgumentsOrEval(JSContext *cx, JSS
         !StringHasPattern(chars, str->length(), eval, mozilla::ArrayLength(eval));
 }
 
 #ifdef JSGC_GENERATIONAL
 void
 PostWriteBarrier(JSRuntime *rt, JSObject *obj)
 {
     JS_ASSERT(!IsInsideNursery(rt, obj));
-    rt->gc.storeBuffer.putWholeCell(obj);
+    rt->gc.storeBuffer.putWholeCellFromMainThread(obj);
 }
 
 void
 PostGlobalWriteBarrier(JSRuntime *rt, JSObject *obj)
 {
     JS_ASSERT(obj->is<GlobalObject>());
     if (!obj->compartment()->globalWriteBarriered) {
         PostWriteBarrier(rt, obj);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1498,17 +1498,17 @@ GeneratorWriteBarrierPre(JSContext *cx, 
     if (zone->needsBarrier())
         MarkGeneratorFrame(zone->barrierTracer(), gen);
 }
 
 static void
 GeneratorWriteBarrierPost(JSContext *cx, JSGenerator *gen)
 {
 #ifdef JSGC_GENERATIONAL
-    cx->runtime()->gc.storeBuffer.putWholeCell(gen->obj);
+    cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(gen->obj);
 #endif
 }
 
 /*
  * Only mark generator frames/slots when the generator is not active on the
  * stack or closed. Barriers when copying onto the stack or closing preserve
  * gc invariants.
  */
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -271,17 +271,17 @@ ToClampedIndex(JSContext *cx, HandleValu
 
 inline void
 PostBarrierTypedArrayObject(JSObject *obj)
 {
 #ifdef JSGC_GENERATIONAL
     JS_ASSERT(obj);
     JSRuntime *rt = obj->runtimeFromMainThread();
     if (!rt->isHeapBusy() && !IsInsideNursery(rt, obj))
-        rt->gc.storeBuffer.putWholeCell(obj);
+        rt->gc.storeBuffer.putWholeCellFromMainThread(obj);
 #endif
 }
 
 inline void
 InitArrayBufferViewDataPointer(ArrayBufferViewObject *obj, ArrayBufferObject *buffer, size_t byteOffset)
 {
     /*
      * N.B. The base of the array's data is stored in the object's
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -37,16 +37,18 @@ NS_NewNumberControlFrame(nsIPresShell* a
   return new (aPresShell) nsNumberControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsNumberControlFrame)
 
 NS_QUERYFRAME_HEAD(nsNumberControlFrame)
   NS_QUERYFRAME_ENTRY(nsNumberControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
+  NS_QUERYFRAME_ENTRY(nsITextControlFrame)
+  NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 nsNumberControlFrame::nsNumberControlFrame(nsStyleContext* aContext)
   : nsContainerFrame(aContext)
   , mHandlingInputEvent(false)
 {
 }
 
@@ -249,16 +251,22 @@ nsNumberControlFrame::AttributeChanged(i
 void
 nsNumberControlFrame::ContentStatesChanged(EventStates aStates)
 {
   if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
     nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));
   }
 }
 
+nsITextControlFrame*
+nsNumberControlFrame::GetTextFieldFrame()
+{
+  return do_QueryFrame(GetAnonTextControl()->GetPrimaryFrame());
+}
+
 nsresult
 nsNumberControlFrame::MakeAnonymousElement(Element** aResult,
                                            nsTArray<ContentInfo>& aElements,
                                            nsIAtom* aTagName,
                                            nsCSSPseudoElements::Type aPseudoType,
                                            nsStyleContext* aParentContext)
 {
   // Get the NodeInfoManager and tag necessary to create the anonymous divs.
@@ -402,16 +410,94 @@ nsNumberControlFrame::CreateAnonymousCon
 }
 
 nsIAtom*
 nsNumberControlFrame::GetType() const
 {
   return nsGkAtoms::numberControlFrame;
 }
 
+NS_IMETHODIMP
+nsNumberControlFrame::GetEditor(nsIEditor **aEditor)
+{
+  return GetTextFieldFrame()->GetEditor(aEditor);
+}
+
+NS_IMETHODIMP
+nsNumberControlFrame::SetSelectionStart(int32_t aSelectionStart)
+{
+  return GetTextFieldFrame()->SetSelectionStart(aSelectionStart);
+}
+
+NS_IMETHODIMP
+nsNumberControlFrame::SetSelectionEnd(int32_t aSelectionEnd)
+{
+  return GetTextFieldFrame()->SetSelectionEnd(aSelectionEnd);
+}
+
+NS_IMETHODIMP
+nsNumberControlFrame::SetSelectionRange(int32_t aSelectionStart,
+                                        int32_t aSelectionEnd,
+                                        SelectionDirection aDirection)
+{
+  return GetTextFieldFrame()->SetSelectionRange(aSelectionStart, aSelectionEnd,
+                                                aDirection);
+}
+
+NS_IMETHODIMP
+nsNumberControlFrame::GetSelectionRange(int32_t* aSelectionStart,
+                                        int32_t* aSelectionEnd,
+                                        SelectionDirection* aDirection)
+{
+  return GetTextFieldFrame()->GetSelectionRange(aSelectionStart, aSelectionEnd,
+                                                aDirection);
+}
+
+NS_IMETHODIMP
+nsNumberControlFrame::GetOwnedSelectionController(nsISelectionController** aSelCon)
+{
+  return GetTextFieldFrame()->GetOwnedSelectionController(aSelCon);
+}
+
+nsFrameSelection*
+nsNumberControlFrame::GetOwnedFrameSelection()
+{
+  return GetTextFieldFrame()->GetOwnedFrameSelection();
+}
+
+nsresult
+nsNumberControlFrame::GetPhonetic(nsAString& aPhonetic)
+{
+  return GetTextFieldFrame()->GetPhonetic(aPhonetic);
+}
+
+nsresult
+nsNumberControlFrame::EnsureEditorInitialized()
+{
+  return GetTextFieldFrame()->EnsureEditorInitialized();
+}
+
+nsresult
+nsNumberControlFrame::ScrollSelectionIntoView()
+{
+  return GetTextFieldFrame()->ScrollSelectionIntoView();
+}
+
+void
+nsNumberControlFrame::SetFocus(bool aOn, bool aRepaint)
+{
+  GetTextFieldFrame()->SetFocus(aOn, aRepaint);
+}
+
+nsresult
+nsNumberControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
+{
+  return GetTextFieldFrame()->SetFormProperty(aName, aValue);
+}
+
 HTMLInputElement*
 nsNumberControlFrame::GetAnonTextControl()
 {
   return mTextField ? HTMLInputElement::FromContent(mTextField) : nullptr;
 }
 
 /* static */ nsNumberControlFrame*
 nsNumberControlFrame::GetNumberControlFrameForTextField(nsIFrame* aFrame)
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsNumberControlFrame_h__
 #define nsNumberControlFrame_h__
 
 #include "mozilla/Attributes.h"
 #include "nsContainerFrame.h"
 #include "nsIFormControlFrame.h"
+#include "nsITextControlFrame.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsCOMPtr.h"
 
 class nsPresContext;
 
 namespace mozilla {
 class WidgetEvent;
 class WidgetGUIEvent;
@@ -22,16 +23,17 @@ class HTMLInputElement;
 }
 }
 
 /**
  * This frame type is used for <input type=number>.
  */
 class nsNumberControlFrame MOZ_FINAL : public nsContainerFrame
                                      , public nsIAnonymousContentCreator
+                                     , public nsITextControlFrame
 {
   friend nsIFrame*
   NS_NewNumberControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   typedef mozilla::dom::Element Element;
   typedef mozilla::dom::HTMLInputElement HTMLInputElement;
   typedef mozilla::WidgetEvent WidgetEvent;
   typedef mozilla::WidgetGUIEvent WidgetGUIEvent;
@@ -78,16 +80,48 @@ public:
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return nsContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
+  // nsITextControlFrame
+  NS_IMETHOD    GetEditor(nsIEditor **aEditor) MOZ_OVERRIDE;
+
+  NS_IMETHOD    SetSelectionStart(int32_t aSelectionStart) MOZ_OVERRIDE;
+  NS_IMETHOD    SetSelectionEnd(int32_t aSelectionEnd) MOZ_OVERRIDE;
+
+  NS_IMETHOD    SetSelectionRange(int32_t aSelectionStart,
+                                  int32_t aSelectionEnd,
+                                  SelectionDirection aDirection = eNone) MOZ_OVERRIDE;
+
+  NS_IMETHOD    GetSelectionRange(int32_t* aSelectionStart,
+                                  int32_t* aSelectionEnd,
+                                  SelectionDirection* aDirection = nullptr) MOZ_OVERRIDE;
+
+  NS_IMETHOD    GetOwnedSelectionController(nsISelectionController** aSelCon) MOZ_OVERRIDE;
+  virtual nsFrameSelection* GetOwnedFrameSelection() MOZ_OVERRIDE;
+
+  virtual nsresult GetPhonetic(nsAString& aPhonetic) MOZ_OVERRIDE;
+
+  /**
+   * Ensure mEditor is initialized with the proper flags and the default value.
+   * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created
+   * @throws various and sundry other things
+   */
+  virtual nsresult EnsureEditorInitialized() MOZ_OVERRIDE;
+
+  virtual nsresult ScrollSelectionIntoView() MOZ_OVERRIDE;
+
+  // nsIFormControlFrame
+  virtual void SetFocus(bool aOn, bool aRepaint) MOZ_OVERRIDE;
+  virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) MOZ_OVERRIDE;
+
   /**
    * This method attempts to localizes aValue and then sets the result as the
    * value of our anonymous text control. It's called when our
    * HTMLInputElement's value changes, when we need to sync up the value
    * displayed in our anonymous text control.
    */
   void SetValueOfAnonTextControl(const nsAString& aValue);
 
@@ -153,16 +187,17 @@ public:
   nsresult HandleSelectCall();
 
   virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
 
   bool ShouldUseNativeStyleForSpinner() const;
 
 private:
 
+  nsITextControlFrame* GetTextFieldFrame();
   nsresult MakeAnonymousElement(Element** aResult,
                                 nsTArray<ContentInfo>& aElements,
                                 nsIAtom* aTagName,
                                 nsCSSPseudoElements::Type aPseudoType,
                                 nsStyleContext* aParentContext);
 
   class SyncDisabledStateEvent;
   friend class SyncDisabledStateEvent;
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -653,17 +653,17 @@ public:
     return mHelper.IsScrollingActive();
   }
   virtual bool IsProcessingAsyncScroll() MOZ_OVERRIDE {
     return mHelper.IsProcessingAsyncScroll();
   }
   virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
     mHelper.ResetScrollPositionForLayerPixelAlignment();
   }
-  virtual bool DidHistoryRestore() MOZ_OVERRIDE {
+  virtual bool DidHistoryRestore() const MOZ_OVERRIDE {
     return mHelper.mDidHistoryRestore;
   }
   virtual void ClearDidHistoryRestore() MOZ_OVERRIDE {
     mHelper.mDidHistoryRestore = false;
   }
   virtual bool IsRectNearlyVisible(const nsRect& aRect) MOZ_OVERRIDE {
     return mHelper.IsRectNearlyVisible(aRect);
   }
@@ -967,17 +967,17 @@ public:
     return mHelper.IsScrollingActive();
   }
   virtual bool IsProcessingAsyncScroll() MOZ_OVERRIDE {
     return mHelper.IsProcessingAsyncScroll();
   }
   virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
     mHelper.ResetScrollPositionForLayerPixelAlignment();
   }
-  virtual bool DidHistoryRestore() MOZ_OVERRIDE {
+  virtual bool DidHistoryRestore() const MOZ_OVERRIDE {
     return mHelper.mDidHistoryRestore;
   }
   virtual void ClearDidHistoryRestore() MOZ_OVERRIDE {
     mHelper.mDidHistoryRestore = false;
   }
   virtual bool IsRectNearlyVisible(const nsRect& aRect) MOZ_OVERRIDE {
     return mHelper.IsRectNearlyVisible(aRect);
   }
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -265,17 +265,17 @@ public:
   /**
    * Call this when the layer(s) induced by active scrolling are being
    * completely redrawn.
    */
   virtual void ResetScrollPositionForLayerPixelAlignment() = 0;
   /**
    * Was the current presentation state for this frame restored from history?
    */
-  virtual bool DidHistoryRestore() = 0;
+  virtual bool DidHistoryRestore() const = 0;
   /**
    * Clear the flag so that DidHistoryRestore() returns false until the next
    * RestoreState call.
    * @see nsIStatefulFrame::RestoreState
    */
   virtual void ClearDidHistoryRestore() = 0;
   /**
    * Determine if the passed in rect is nearly visible according to the image
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -989,17 +989,17 @@ Declaration::GetValue(nsCSSProperty aPro
         aValue.Append(char16_t(' '));
         AppendValueToString(eCSSProperty_grid_auto_columns,
                             aValue, aSerialization);
         aValue.AppendLiteral(" / ");
         AppendValueToString(eCSSProperty_grid_auto_rows,
                             aValue, aSerialization);
         break;
       } else if (!(autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
-                   autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_NONE &&
+                   autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_ROW &&
                    autoColumnsValue.GetUnit() == eCSSUnit_Auto &&
                    autoRowsValue.GetUnit() == eCSSUnit_Auto)) {
         // Not serializable, bail.
         return;
       }
       // Fall through to eCSSProperty_grid_template
     }
     case eCSSProperty_grid_template: {
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -503,16 +503,17 @@ CSS_KEY(small-caption, small_caption)
 CSS_KEY(smaller, smaller)
 CSS_KEY(soft, soft)
 CSS_KEY(soft-light, soft_light)
 CSS_KEY(solid, solid)
 CSS_KEY(space-around, space_around)
 CSS_KEY(space-between, space_between)
 CSS_KEY(span, span)
 CSS_KEY(square, square)
+CSS_KEY(stack, stack)
 CSS_KEY(stacked-fractions, stacked_fractions)
 CSS_KEY(start, start)
 CSS_KEY(static, static)
 CSS_KEY(status-bar, status_bar)
 CSS_KEY(step-end, step_end)
 CSS_KEY(step-start, step_start)
 CSS_KEY(sticky, sticky)
 CSS_KEY(stretch, stretch)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -689,17 +689,16 @@ protected:
                                   nsDataHashtable<nsStringHashKey, uint32_t>& aAreaIndices);
   bool ParseGridTemplateAreas();
   bool ParseGridTemplate();
   bool ParseGridTemplateAfterSlash(bool aColumnsIsTrackList);
   bool ParseGridTemplateAfterString(const nsCSSValue& aFirstLineNames);
   bool ParseGrid();
   bool ParseGridShorthandAutoProps();
   bool ParseGridLine(nsCSSValue& aValue);
-  bool ParseGridAutoPosition();
   bool ParseGridColumnRowStartEnd(nsCSSProperty aPropID);
   bool ParseGridColumnRow(nsCSSProperty aStartPropID,
                           nsCSSProperty aEndPropID);
   bool ParseGridArea();
 
   // for 'clip' and '-moz-image-region'
   bool ParseRect(nsCSSProperty aPropID);
   bool ParseColumns();
@@ -6947,35 +6946,36 @@ CSSParserImpl::ParseGridAutoFlow()
 {
   nsCSSValue value;
   if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
     AppendValue(eCSSProperty_grid_auto_flow, value);
     return true;
   }
 
   static const int32_t mask[] = {
-    NS_STYLE_GRID_AUTO_FLOW_COLUMN | NS_STYLE_GRID_AUTO_FLOW_ROW,
+    NS_STYLE_GRID_AUTO_FLOW_ROW | NS_STYLE_GRID_AUTO_FLOW_COLUMN,
+    NS_STYLE_GRID_AUTO_FLOW_DENSE | NS_STYLE_GRID_AUTO_FLOW_STACK,
     MASK_END_VALUE
   };
   if (!ParseBitmaskValues(value, nsCSSProps::kGridAutoFlowKTable, mask)) {
     return false;
   }
   int32_t bitField = value.GetIntValue();
 
   // Requires one of these
-  if (!(bitField & NS_STYLE_GRID_AUTO_FLOW_NONE ||
+  if (!(bitField & NS_STYLE_GRID_AUTO_FLOW_ROW ||
         bitField & NS_STYLE_GRID_AUTO_FLOW_COLUMN ||
-        bitField & NS_STYLE_GRID_AUTO_FLOW_ROW)) {
-    return false;
-  }
-
-  // 'none' is only valid if it occurs alone:
-  if (bitField & NS_STYLE_GRID_AUTO_FLOW_NONE &&
-      bitField != NS_STYLE_GRID_AUTO_FLOW_NONE) {
-    return false;
+        bitField & NS_STYLE_GRID_AUTO_FLOW_STACK)) {
+    return false;
+  }
+
+  // 'stack' without 'row' or 'column' defaults to 'stack row'
+  if (bitField == NS_STYLE_GRID_AUTO_FLOW_STACK) {
+    value.SetIntValue(bitField | NS_STYLE_GRID_AUTO_FLOW_ROW,
+                      eCSSUnit_Enumerated);
   }
 
   AppendValue(eCSSProperty_grid_auto_flow, value);
   return true;
 }
 
 CSSParseResult
 CSSParserImpl::ParseGridLineNames(nsCSSValue& aValue)
@@ -7820,58 +7820,38 @@ CSSParserImpl::ParseGrid()
     for (const nsCSSProperty* subprops =
            nsCSSProps::SubpropertyEntryFor(eCSSProperty_grid);
          *subprops != eCSSProperty_UNKNOWN; ++subprops) {
       AppendValue(*subprops, value);
     }
     return true;
   }
 
-  // 'none' at the beginning could be a <'grid-auto-flow'>
-  // (which also covers 'none' by itself)
-  // or a <'grid-template-columns'> (as part of <'grid-template'>)
-  if (ParseVariant(value, VARIANT_NONE, nullptr)) {
-    if (ExpectSymbol('/', true)) {
-      AppendValue(eCSSProperty_grid_template_columns, value);
-
-      // Set grid-auto-* subproperties to their initial values.
-      value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_NONE, eCSSUnit_Enumerated);
-      AppendValue(eCSSProperty_grid_auto_flow, value);
-      value.SetAutoValue();
-      AppendValue(eCSSProperty_grid_auto_columns, value);
-      AppendValue(eCSSProperty_grid_auto_rows, value);
-
-      return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ false);
-    }
-    value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_NONE, eCSSUnit_Enumerated);
-    AppendValue(eCSSProperty_grid_auto_flow, value);
-    return ParseGridShorthandAutoProps();
-  }
-
   // An empty value is always invalid.
   if (!GetToken(true)) {
     return false;
   }
 
-  // If the value starts with a 'dense', 'column' or 'row' keyword,
-  // it can only start with a <'grid-auto-flow'>
+  // The values starts with a <'grid-auto-flow'> if and only if
+  // it starts with a 'stack', 'dense', 'column' or 'row' keyword.
   if (mToken.mType == eCSSToken_Ident) {
     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
-    if (keyword == eCSSKeyword_dense ||
+    if (keyword == eCSSKeyword_stack ||
+        keyword == eCSSKeyword_dense ||
         keyword == eCSSKeyword_column ||
         keyword == eCSSKeyword_row) {
       UngetToken();
       return ParseGridAutoFlow() && ParseGridShorthandAutoProps();
     }
   }
   UngetToken();
 
   // Set other subproperties to their initial values
   // and parse <'grid-template'>.
-  value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_NONE, eCSSUnit_Enumerated);
+  value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_ROW, eCSSUnit_Enumerated);
   AppendValue(eCSSProperty_grid_auto_flow, value);
   value.SetAutoValue();
   AppendValue(eCSSProperty_grid_auto_columns, value);
   AppendValue(eCSSProperty_grid_auto_rows, value);
   return ParseGridTemplate();
 }
 
 // Parse [ <'grid-auto-columns'> [ / <'grid-auto-rows'> ]? ]?
@@ -8006,36 +7986,16 @@ CSSParserImpl::ParseGridLine(nsCSSValue&
   }
   if (hasIdent) {
     item->mValue = ident;
   }
   return true;
 }
 
 bool
-CSSParserImpl::ParseGridAutoPosition()
-{
-  nsCSSValue value;
-  if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
-    AppendValue(eCSSProperty_grid_auto_position, value);
-    return true;
-  }
-  nsCSSValue columnStartValue;
-  nsCSSValue rowStartValue;
-  if (ParseGridLine(columnStartValue) &&
-      ExpectSymbol('/', true) &&
-      ParseGridLine(rowStartValue)) {
-    value.SetPairValue(columnStartValue, rowStartValue);
-    AppendValue(eCSSProperty_grid_auto_position, value);
-    return true;
-  }
-  return false;
-}
-
-bool
 CSSParserImpl::ParseGridColumnRowStartEnd(nsCSSProperty aPropID)
 {
   nsCSSValue value;
   if (ParseVariant(value, VARIANT_INHERIT, nullptr) ||
       ParseGridLine(value)) {
     AppendValue(aPropID, value);
     return true;
   }
@@ -9174,18 +9134,16 @@ CSSParserImpl::ParsePropertyByFunction(n
     return ParseGridTemplateAreas();
   case eCSSProperty_grid_template_columns:
   case eCSSProperty_grid_template_rows:
     return ParseGridTemplateColumnsRows(aPropID);
   case eCSSProperty_grid_template:
     return ParseGridTemplate();
   case eCSSProperty_grid:
     return ParseGrid();
-  case eCSSProperty_grid_auto_position:
-    return ParseGridAutoPosition();
   case eCSSProperty_grid_column_start:
   case eCSSProperty_grid_column_end:
   case eCSSProperty_grid_row_start:
   case eCSSProperty_grid_row_end:
     return ParseGridColumnRowStartEnd(aPropID);
   case eCSSProperty_grid_column:
     return ParseGridColumnRow(eCSSProperty_grid_column_start,
                               eCSSProperty_grid_column_end);
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2030,26 +2030,16 @@ CSS_PROP_POSITION(
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_STORES_CALC,
     "layout.css.grid.enabled",
     0,
     kGridTrackBreadthKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_POSITION(
-    grid-auto-position,
-    grid_auto_position,
-    GridAutoPosition,
-    CSS_PROPERTY_PARSE_FUNCTION,
-    "layout.css.grid.enabled",
-    0,
-    nullptr,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_POSITION(
     grid-template-areas,
     grid_template_areas,
     GridTemplateAreas,
     CSS_PROPERTY_PARSE_FUNCTION,
     "layout.css.grid.enabled",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1233,19 +1233,19 @@ const KTableValue nsCSSProps::kFontWeigh
   eCSSKeyword_normal, NS_STYLE_FONT_WEIGHT_NORMAL,
   eCSSKeyword_bold, NS_STYLE_FONT_WEIGHT_BOLD,
   eCSSKeyword_bolder, NS_STYLE_FONT_WEIGHT_BOLDER,
   eCSSKeyword_lighter, NS_STYLE_FONT_WEIGHT_LIGHTER,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kGridAutoFlowKTable[] = {
-  eCSSKeyword_none, NS_STYLE_GRID_AUTO_FLOW_NONE,
+  eCSSKeyword_stack, NS_STYLE_GRID_AUTO_FLOW_STACK,
+  eCSSKeyword_row, NS_STYLE_GRID_AUTO_FLOW_ROW,
   eCSSKeyword_column, NS_STYLE_GRID_AUTO_FLOW_COLUMN,
-  eCSSKeyword_row, NS_STYLE_GRID_AUTO_FLOW_ROW,
   eCSSKeyword_dense, NS_STYLE_GRID_AUTO_FLOW_DENSE,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kGridTrackBreadthKTable[] = {
   eCSSKeyword_min_content, NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
   eCSSKeyword_max_content, NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
   eCSSKeyword_UNKNOWN,-1
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -1027,22 +1027,21 @@ nsCSSValue::AppendToString(nsCSSProperty
       nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
                                          NS_FONT_VARIANT_NUMERIC_LINING,
                                          NS_FONT_VARIANT_NUMERIC_ORDINAL,
                                          aResult);
       break;
 
     case eCSSProperty_grid_auto_flow:
       nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
-                                         NS_STYLE_GRID_AUTO_FLOW_NONE,
+                                         NS_STYLE_GRID_AUTO_FLOW_STACK,
                                          NS_STYLE_GRID_AUTO_FLOW_DENSE,
                                          aResult);
       break;
 
-    case eCSSProperty_grid_auto_position:
     case eCSSProperty_grid_column_start:
     case eCSSProperty_grid_column_end:
     case eCSSProperty_grid_row_start:
     case eCSSProperty_grid_row_end:
       // "span" is the only enumerated-unit value for these properties
       aResult.AppendLiteral("span");
       break;
 
@@ -1321,20 +1320,16 @@ nsCSSValue::AppendToString(nsCSSProperty
 
       // functional values
       const nsCSSValueList *list = GetPairValue().mYValue.GetListValue();
       nsAutoTArray<gfxAlternateValue,8> altValues;
 
       nsStyleUtil::ComputeFunctionalAlternates(list, altValues);
       nsStyleUtil::SerializeFunctionalAlternates(altValues, out);
       aResult.Append(out);
-    } else if (eCSSProperty_grid_auto_position == aProperty) {
-      GetPairValue().mXValue.AppendToString(aProperty, aResult, aSerialization);
-      aResult.AppendLiteral(" / ");
-      GetPairValue().mYValue.AppendToString(aProperty, aResult, aSerialization);
     } else {
       GetPairValue().AppendToString(aProperty, aResult, aSerialization);
     }
   } else if (eCSSUnit_Triplet == unit) {
     GetTripletValue().AppendToString(aProperty, aResult, aSerialization);
   } else if (eCSSUnit_Rect == unit) {
     GetRectValue().AppendToString(aProperty, aResult, aSerialization);
   } else if (eCSSUnit_List == unit || eCSSUnit_ListDep == unit) {
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2393,17 +2393,17 @@ nsComputedDOMStyle::GetGridTemplateColum
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetGridAutoFlow()
 {
   nsAutoString str;
   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow,
                                      StylePosition()->mGridAutoFlow,
-                                     NS_STYLE_GRID_AUTO_FLOW_NONE,
+                                     NS_STYLE_GRID_AUTO_FLOW_STACK,
                                      NS_STYLE_GRID_AUTO_FLOW_DENSE,
                                      str);
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
   val->SetString(str);
   return val;
 }
 
 CSSValue*
@@ -2464,34 +2464,16 @@ nsComputedDOMStyle::GetGridLine(const ns
   }
 
   NS_ASSERTION(valueList->Length() > 0,
                "Should have appended at least one value");
   return valueList;
 }
 
 CSSValue*
-nsComputedDOMStyle::DoGetGridAutoPosition()
-{
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
-
-  valueList->AppendCSSValue(
-    GetGridLine(StylePosition()->mGridAutoPositionColumn));
-
-  nsROCSSPrimitiveValue* slash = new nsROCSSPrimitiveValue;
-  slash->SetString(NS_LITERAL_STRING("/"));
-  valueList->AppendCSSValue(slash);
-
-  valueList->AppendCSSValue(
-    GetGridLine(StylePosition()->mGridAutoPositionRow));
-
-  return valueList;
-}
-
-CSSValue*
 nsComputedDOMStyle::DoGetGridColumnStart()
 {
   return GetGridLine(StylePosition()->mGridColumnStart);
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetGridColumnEnd()
 {
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -263,17 +263,16 @@ private:
   mozilla::dom::CSSValue* DoGetFontVariantNumeric();
   mozilla::dom::CSSValue* DoGetFontVariantPosition();
   mozilla::dom::CSSValue* DoGetFontWeight();
 
   /* Grid properties */
   mozilla::dom::CSSValue* DoGetGridAutoFlow();
   mozilla::dom::CSSValue* DoGetGridAutoColumns();
   mozilla::dom::CSSValue* DoGetGridAutoRows();
-  mozilla::dom::CSSValue* DoGetGridAutoPosition();
   mozilla::dom::CSSValue* DoGetGridTemplateAreas();
   mozilla::dom::CSSValue* DoGetGridTemplateColumns();
   mozilla::dom::CSSValue* DoGetGridTemplateRows();
   mozilla::dom::CSSValue* DoGetGridColumnStart();
   mozilla::dom::CSSValue* DoGetGridColumnEnd();
   mozilla::dom::CSSValue* DoGetGridRowStart();
   mozilla::dom::CSSValue* DoGetGridRowEnd();
 
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -127,17 +127,16 @@ COMPUTED_STYLE_PROP(font_variant_alterna
 COMPUTED_STYLE_PROP(font_variant_caps,             FontVariantCaps)
 COMPUTED_STYLE_PROP(font_variant_east_asian,       FontVariantEastAsian)
 COMPUTED_STYLE_PROP(font_variant_ligatures,        FontVariantLigatures)
 COMPUTED_STYLE_PROP(font_variant_numeric,          FontVariantNumeric)
 COMPUTED_STYLE_PROP(font_variant_position,         FontVariantPosition)
 COMPUTED_STYLE_PROP(font_weight,                   FontWeight)
 COMPUTED_STYLE_PROP(grid_auto_columns,             GridAutoColumns)
 COMPUTED_STYLE_PROP(grid_auto_flow,                GridAutoFlow)
-COMPUTED_STYLE_PROP(grid_auto_position,            GridAutoPosition)
 COMPUTED_STYLE_PROP(grid_auto_rows,                GridAutoRows)
 COMPUTED_STYLE_PROP(grid_column_end,               GridColumnEnd)
 COMPUTED_STYLE_PROP(grid_column_start,             GridColumnStart)
 COMPUTED_STYLE_PROP(grid_row_end,                  GridRowEnd)
 COMPUTED_STYLE_PROP(grid_row_start,                GridRowStart)
 COMPUTED_STYLE_PROP(grid_template_areas,           GridTemplateAreas)
 COMPUTED_STYLE_PROP(grid_template_columns,         GridTemplateColumns)
 COMPUTED_STYLE_PROP(grid_template_rows,            GridTemplateRows)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -7500,17 +7500,17 @@ nsRuleNode::ComputePositionData(void* aS
     case eCSSUnit_Null:
       break;
     case eCSSUnit_Inherit:
       canStoreInRuleTree = false;
       pos->mGridAutoFlow = parentPos->mGridAutoFlow;
       break;
     case eCSSUnit_Initial:
     case eCSSUnit_Unset:
-      pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_NONE;
+      pos->mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_ROW;
       break;
     default:
       NS_ASSERTION(gridAutoFlow.GetUnit() == eCSSUnit_Enumerated,
                    "Unexpected unit");
       pos->mGridAutoFlow = gridAutoFlow.GetIntValue();
   }
 
   // grid-auto-columns
@@ -7540,43 +7540,16 @@ nsRuleNode::ComputePositionData(void* aS
                    aContext, mPresContext, canStoreInRuleTree);
 
   // grid-tempate-areas
   SetGridTemplateAreas(*aRuleData->ValueForGridTemplateAreas(),
                        &pos->mGridTemplateAreas,
                        parentPos->mGridTemplateAreas,
                        canStoreInRuleTree);
 
-  // grid-auto-position
-  const nsCSSValue& gridAutoPosition = *aRuleData->ValueForGridAutoPosition();
-  switch (gridAutoPosition.GetUnit()) {
-    case eCSSUnit_Null:
-      break;
-    case eCSSUnit_Inherit:
-      canStoreInRuleTree = false;
-      pos->mGridAutoPositionColumn = parentPos->mGridAutoPositionColumn;
-      pos->mGridAutoPositionRow = parentPos->mGridAutoPositionRow;
-      break;
-    case eCSSUnit_Initial:
-    case eCSSUnit_Unset:
-      // '1 / 1'
-      pos->mGridAutoPositionColumn.SetToInteger(1);
-      pos->mGridAutoPositionRow.SetToInteger(1);
-      break;
-    default:
-      SetGridLine(gridAutoPosition.GetPairValue().mXValue,
-                  pos->mGridAutoPositionColumn,
-                  parentPos->mGridAutoPositionColumn,
-                  canStoreInRuleTree);
-      SetGridLine(gridAutoPosition.GetPairValue().mYValue,
-                  pos->mGridAutoPositionRow,
-                  parentPos->mGridAutoPositionRow,
-                  canStoreInRuleTree);
-  }
-
   // grid-column-start
   SetGridLine(*aRuleData->ValueForGridColumnStart(),
               pos->mGridColumnStart,
               parentPos->mGridColumnStart,
               canStoreInRuleTree);
 
   // grid-column-end
   SetGridLine(*aRuleData->ValueForGridColumnEnd(),
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -539,19 +539,19 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_FONT_INFO                      11
 #define NS_STYLE_FONT_DIALOG                    12
 #define NS_STYLE_FONT_BUTTON                    13
 #define NS_STYLE_FONT_PULL_DOWN_MENU            14
 #define NS_STYLE_FONT_LIST                      15
 #define NS_STYLE_FONT_FIELD                     16
 
 // grid-auto-flow keywords
-#define NS_STYLE_GRID_AUTO_FLOW_NONE            (1 << 0)
-#define NS_STYLE_GRID_AUTO_FLOW_COLUMN          (1 << 1)
-#define NS_STYLE_GRID_AUTO_FLOW_ROW             (1 << 2)
+#define NS_STYLE_GRID_AUTO_FLOW_STACK           (1 << 0)
+#define NS_STYLE_GRID_AUTO_FLOW_ROW             (1 << 1)
+#define NS_STYLE_GRID_AUTO_FLOW_COLUMN          (1 << 2)
 #define NS_STYLE_GRID_AUTO_FLOW_DENSE           (1 << 3)
 
 // 'subgrid' keyword in grid-template-{columns,rows}
 #define NS_STYLE_GRID_TEMPLATE_SUBGRID          0
 
 // CSS Grid <track-breadth> keywords
 // Should not overlap with NS_STYLE_GRID_TEMPLATE_SUBGRID
 #define NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT 1
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1238,48 +1238,44 @@ nsStylePosition::nsStylePosition(void)
                                   eStyleUnit_Enumerated);
   mGridAutoColumnsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
                                   eStyleUnit_Enumerated);
   mGridAutoRowsMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
                                eStyleUnit_Enumerated);
   mGridAutoRowsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
                                eStyleUnit_Enumerated);
 
-  mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_NONE;
+  mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_ROW;
   mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
   mAlignContent = NS_STYLE_ALIGN_CONTENT_STRETCH;
   mAlignItems = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
   mAlignSelf = NS_STYLE_ALIGN_SELF_AUTO;
   mFlexDirection = NS_STYLE_FLEX_DIRECTION_ROW;
   mFlexWrap = NS_STYLE_FLEX_WRAP_NOWRAP;
   mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_FLEX_START;
   mOrder = NS_STYLE_ORDER_INITIAL;
   mFlexGrow = 0.0f;
   mFlexShrink = 1.0f;
   mZIndex.SetAutoValue();
-  mGridAutoPositionColumn.SetToInteger(1);
-  mGridAutoPositionRow.SetToInteger(1);
   // Other members get their default constructors
   // which initialize them to representations of their respective initial value.
   // mGridTemplateAreas: nullptr for 'none'
   // mGridTemplate{Rows,Columns}: false and empty arrays for 'none'
   // mGrid{Column,Row}{Start,End}: false/0/empty values for 'auto'
 }
 
 nsStylePosition::~nsStylePosition(void)
 {
   MOZ_COUNT_DTOR(nsStylePosition);
 }
 
 nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
   : mGridTemplateColumns(aSource.mGridTemplateColumns)
   , mGridTemplateRows(aSource.mGridTemplateRows)
   , mGridTemplateAreas(aSource.mGridTemplateAreas)
-  , mGridAutoPositionColumn(aSource.mGridAutoPositionColumn)
-  , mGridAutoPositionRow(aSource.mGridAutoPositionRow)
   , mGridColumnStart(aSource.mGridColumnStart)
   , mGridColumnEnd(aSource.mGridColumnEnd)
   , mGridRowStart(aSource.mGridRowStart)
   , mGridRowEnd(aSource.mGridRowEnd)
 {
   MOZ_COUNT_CTOR(nsStylePosition);
   // If you add any memcpy'able member vars,
   // they should be declared before mGridTemplateColumns.
@@ -1287,18 +1283,16 @@ nsStylePosition::nsStylePosition(const n
   // they should be declared after mGridTemplateColumns,
   // and you should invoke their copy constructor in the init list above
   // and update this static-assert to include their "sizeof()"
   static_assert(sizeof(nsStylePosition) ==
                 offsetof(nsStylePosition, mGridTemplateColumns) +
                 sizeof(mGridTemplateColumns) +
                 sizeof(mGridTemplateRows) +
                 sizeof(mGridTemplateAreas) +
-                sizeof(mGridAutoPositionColumn) +
-                sizeof(mGridAutoPositionRow) +
                 sizeof(mGridColumnStart) +
                 sizeof(mGridColumnEnd) +
                 sizeof(mGridRowStart) +
                 sizeof(mGridRowEnd),
                 "Unexpected size or offset in nsStylePosition");
   memcpy((nsStylePosition*) this,
          &aSource,
          offsetof(nsStylePosition, mGridTemplateColumns));
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1311,20 +1311,16 @@ struct nsStylePosition {
   // See nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
   // in nsStyleStruct.cpp
   nsStyleGridTemplate mGridTemplateColumns;
   nsStyleGridTemplate mGridTemplateRows;
 
   // nullptr for 'none'
   nsRefPtr<mozilla::css::GridTemplateAreasValue> mGridTemplateAreas;
 
-  // We represent the "grid-auto-position" property in two parts:
-  nsStyleGridLine mGridAutoPositionColumn;
-  nsStyleGridLine mGridAutoPositionRow;
-
   nsStyleGridLine mGridColumnStart;
   nsStyleGridLine mGridColumnEnd;
   nsStyleGridLine mGridRowStart;
   nsStyleGridLine mGridRowEnd;
 
   bool WidthDependsOnContainer() const
     { return WidthCoordDependsOnContainer(mWidth); }
   bool MinWidthDependsOnContainer() const
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4797,32 +4797,36 @@ if (SpecialPowers.getBoolPref("layout.cs
 }
 
 if (SpecialPowers.getBoolPref("layout.css.grid.enabled")) {
   gCSSProperties["display"].other_values.push("grid", "inline-grid");
   gCSSProperties["grid-auto-flow"] = {
     domProp: "gridAutoFlow",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
-    initial_values: [ "none" ],
+    initial_values: [ "row" ],
     other_values: [
       "column",
-      "row",
       "column dense",
       "row dense",
       "dense column",
       "dense row",
+      "stack column",
+      "stack row",
+      "stack",
     ],
     invalid_values: [
       "",
       "auto",
+      "none",
       "10px",
       "dense",
-      "none row",
-      "none dense",
+      "stack dense",
+      "stack stack",
+      "stack row stack",
       "column row",
       "dense row dense",
     ]
   };
 
   gCSSProperties["grid-auto-columns"] = {
     domProp: "gridAutoColumns",
     inherited: false,
@@ -5041,37 +5045,35 @@ if (SpecialPowers.getBoolPref("layout.cs
       "grid-template-rows",
       "grid-auto-flow",
       "grid-auto-columns",
       "grid-auto-rows",
     ],
     initial_values: [
       "none",
       "none / none",
-      "none auto",
-      "none auto / auto",
     ],
     other_values: [
-      "row",
-      "none 40px",
+      "stack 40px",
       "column dense auto",
       "dense row minmax(min-content, 2fr)",
       "row 40px / 100px",
     ].concat(
       gCSSProperties["grid-template"].other_values,
       gCSSProperties["grid-auto-flow"].other_values
     ),
     invalid_values: [
       "row column 40px",
       "row -20px",
       "row 200ms",
       "row 40px 100px",
     ].concat(
       gCSSProperties["grid-template"].invalid_values,
       gCSSProperties["grid-auto-flow"].invalid_values
+        .filter((v) => v != 'none')
     )
   };
 
   var gridLineOtherValues = [
     "foo",
     "2",
     "2 foo",
     "foo 2",
@@ -5139,56 +5141,31 @@ if (SpecialPowers.getBoolPref("layout.cs
     domProp: "gridRowEnd",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto" ],
     other_values: gridLineOtherValues,
     invalid_values: gridLineInvalidValues
   };
 
-  var gridAutoPositionOtherValues = [];
+  // The grid-column and grid-row shorthands take values of the form
+  //   <grid-line> [ / <grid-line> ]?
+  var gridColumnRowOtherValues = [].concat(gridLineOtherValues);
   gridLineOtherValues.concat([ "auto" ]).forEach(function(val) {
-    gridAutoPositionOtherValues.push(" foo / " + val);
-    gridAutoPositionOtherValues.push(val + "/2");
+    gridColumnRowOtherValues.push(" foo / " + val);
+    gridColumnRowOtherValues.push(val + "/2");
   });
-  var gridAutoPositionInvalidValues = [
-    "foo",
+  var gridColumnRowInvalidValues = [
     "foo, bar",
     "foo / bar / baz",
-  ];
+  ].concat(gridLineInvalidValues);
   gridLineInvalidValues.forEach(function(val) {
-    gridAutoPositionInvalidValues.push("span 3 / " + val);
-    gridAutoPositionInvalidValues.push(val + " / foo");
+    gridColumnRowInvalidValues.push("span 3 / " + val);