Merge mozilla-central to mozilla-inbound
authorEd Morley <bmo@edmorley.co.uk>
Fri, 10 Feb 2012 14:03:24 +0000
changeset 86732 82612a816cc0f7af875639a9eb023fd040c8c21b
parent 86702 40c36f6068d69afb75afa6633bf129fbdd553f58 (current diff)
parent 86731 157ec7365fb9d179d631e0a17232d2d9bcf6dd00 (diff)
child 86733 c09af9f27313980150073c0e1fcb55a807d06089
push id102
push userMs2ger@gmail.com
push dateFri, 10 Feb 2012 20:38:19 +0000
milestone13.0a1
Merge mozilla-central to mozilla-inbound
browser/base/content/browser.js
--- a/browser/base/content/browser-thumbnails.js
+++ b/browser/base/content/browser-thumbnails.js
@@ -72,20 +72,18 @@ let gBrowserThumbnails = {
   onStateChange: function Thumbnails_onStateChange(aBrowser, aWebProgress,
                                                    aRequest, aStateFlags, aStatus) {
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
       this._delayedCapture(aBrowser);
   },
 
   _capture: function Thumbnails_capture(aBrowser) {
-    if (this._shouldCapture(aBrowser)) {
-      let canvas = this._pageThumbs.capture(aBrowser.contentWindow);
-      this._pageThumbs.store(aBrowser.currentURI.spec, canvas);
-    }
+    if (this._shouldCapture(aBrowser))
+      this._pageThumbs.captureAndStore(aBrowser);
   },
 
   _delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
     if (this._timeouts.has(aBrowser))
       clearTimeout(this._timeouts.get(aBrowser));
     else
       aBrowser.addEventListener("scroll", this, true);
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1223,22 +1223,22 @@ function BrowserStartup() {
   //                      ignored).
   //                 [1]: character set (string)
   //                 [2]: referrer (nsIURI)
   //                 [3]: postData (nsIInputStream)
   //                 [4]: allowThirdPartyFixup (bool)
   if ("arguments" in window && window.arguments[0])
     uriToLoad = window.arguments[0];
 
-  var isLoadingBlank = uriToLoad == "about:blank";
+  var isLoadingBlank = isBlankPageURL(uriToLoad);
   var mustLoadSidebar = false;
 
   prepareForStartup();
 
-  if (uriToLoad && !isLoadingBlank) {
+  if (uriToLoad && uriToLoad != "about:blank") {
     if (uriToLoad instanceof Ci.nsISupportsArray) {
       let count = uriToLoad.Count();
       let specs = [];
       for (let i = 0; i < count; i++) {
         let urisstring = uriToLoad.GetElementAt(i).QueryInterface(Ci.nsISupportsString);
         specs.push(urisstring.data);
       }
 
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -67,21 +67,23 @@ let PageThumbs = {
    * @return The thumbnail image's url.
    */
   getThumbnailURL: function PageThumbs_getThumbnailURL(aUrl) {
     return this.scheme + "://" + this.staticHost +
            "?url=" + encodeURIComponent(aUrl);
   },
 
   /**
-   * Creates a canvas containing a thumbnail depicting the given window.
+   * Captures a thumbnail for the given window.
    * @param aWindow The DOM window to capture a thumbnail from.
-   * @return The newly created canvas containing the image data.
+   * @param aCallback The function to be called when the thumbnail has been
+   *                  captured. The first argument will be the data stream
+   *                  containing the image data.
    */
-  capture: function PageThumbs_capture(aWindow) {
+  capture: function PageThumbs_capture(aWindow, aCallback) {
     let telemetryCaptureTime = new Date();
     let [sw, sh, scale] = this._determineCropSize(aWindow);
 
     let canvas = this._createCanvas();
     let ctx = canvas.getContext("2d");
 
     // Scale the canvas accordingly.
     ctx.scale(scale, scale);
@@ -89,85 +91,65 @@ let PageThumbs = {
     try {
       // Draw the window contents to the canvas.
       ctx.drawWindow(aWindow, 0, 0, sw, sh, THUMBNAIL_BG_COLOR,
                      ctx.DRAWWINDOW_DO_NOT_FLUSH);
     } catch (e) {
       // We couldn't draw to the canvas for some reason.
     }
 
-    Services.telemetry.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
+    let telemetry = Services.telemetry;
+    telemetry.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
       .add(new Date() - telemetryCaptureTime);
 
-    return canvas;
+    canvas.mozFetchAsStream(aCallback, this.contentType);
   },
 
   /**
-   * Stores the image data contained in the given canvas to the underlying
-   * storage.
-   * @param aKey The key to use for the storage.
-   * @param aCanvas The canvas containing the thumbnail's image data.
-   * @param aCallback The function to be called when the canvas data has been
-   *                  stored (optional).
+   * Captures a thumbnail for the given browser and stores it to the cache.
+   * @param aBrowser The browser to capture a thumbnail for.
+   * @param aCallback The function to be called when finished (optional).
    */
-  store: function PageThumbs_store(aKey, aCanvas, aCallback) {
-    let telemetryStoreTime = new Date();
+  captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
+    this.capture(aBrowser.contentWindow, function (aInputStream) {
+      let telemetryStoreTime = new Date();
 
-    function finish(aSuccessful) {
-      if (aSuccessful) {
-        Services.telemetry.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS")
-          .add(new Date() - telemetryStoreTime);
+      function finish(aSuccessful) {
+        if (aSuccessful) {
+          Services.telemetry.getHistogramById("FX_THUMBNAILS_STORE_TIME_MS")
+            .add(new Date() - telemetryStoreTime);
+        }
+
+        if (aCallback)
+          aCallback(aSuccessful);
       }
 
-      if (aCallback)
-        aCallback(aSuccessful);
-    }
-
-    let self = this;
+      // Get a writeable cache entry.
+      PageThumbsCache.getWriteEntry(aBrowser.currentURI.spec, function (aEntry) {
+        if (!aEntry) {
+          finish(false);
+          return;
+        }
 
-    // Get a writeable cache entry.
-    PageThumbsCache.getWriteEntry(aKey, function (aEntry) {
-      if (!aEntry) {
-        finish(false);
-        return;
-      }
-
-      // Extract image data from the canvas.
-      self._readImageData(aCanvas, function (aData) {
         let outputStream = aEntry.openOutputStream(0);
 
         // Write the image data to the cache entry.
-        NetUtil.asyncCopy(aData, outputStream, function (aResult) {
+        NetUtil.asyncCopy(aInputStream, outputStream, function (aResult) {
           let success = Components.isSuccessCode(aResult);
           if (success)
             aEntry.markValid();
 
           aEntry.close();
           finish(success);
         });
       });
     });
   },
 
   /**
-   * Reads the image data from a given canvas and passes it to the callback.
-   * @param aCanvas The canvas to read the image data from.
-   * @param aCallback The function that the image data is passed to.
-   */
-  _readImageData: function PageThumbs_readImageData(aCanvas, aCallback) {
-    let dataUri = aCanvas.toDataURL(PageThumbs.contentType, "");
-    let uri = Services.io.newURI(dataUri, "UTF8", null);
-
-    NetUtil.asyncFetch(uri, function (aData, aResult) {
-      if (Components.isSuccessCode(aResult) && aData && aData.available())
-        aCallback(aData);
-    });
-  },
-
-  /**
    * Determines the crop size for a given content window.
    * @param aWindow The content window.
    * @return An array containing width, height and scale.
    */
   _determineCropSize: function PageThumbs_determineCropSize(aWindow) {
     let sw = aWindow.innerWidth;
     let sh = aWindow.innerHeight;
 
--- a/browser/components/thumbnails/test/head.js
+++ b/browser/components/thumbnails/test/head.js
@@ -89,25 +89,22 @@ function whenLoaded(aElement, aCallback)
  * Captures a screenshot for the currently selected tab, stores it in the cache,
  * retrieves it from the cache and compares pixel color values.
  * @param aRed The red component's intensity.
  * @param aGreen The green component's intensity.
  * @param aBlue The blue component's intensity.
  * @param aMessage The info message to print when comparing the pixel color.
  */
 function captureAndCheckColor(aRed, aGreen, aBlue, aMessage) {
-  let window = gBrowser.selectedTab.linkedBrowser.contentWindow;
-
-  let key = Date.now();
-  let data = PageThumbs.capture(window);
+  let browser = gBrowser.selectedBrowser;
 
-  // Store the thumbnail in the cache.
-  PageThumbs.store(key, data, function () {
+  // Capture the screenshot.
+  PageThumbs.captureAndStore(browser, function () {
     let width = 100, height = 100;
-    let thumb = PageThumbs.getThumbnailURL(key, width, height);
+    let thumb = PageThumbs.getThumbnailURL(browser.currentURI.spec, width, height);
 
     getXULDocument(function (aDocument) {
       let htmlns = "http://www.w3.org/1999/xhtml";
       let img = aDocument.createElementNS(htmlns, "img");
       img.setAttribute("src", thumb);
 
       whenLoaded(img, function () {
         let canvas = aDocument.createElementNS(htmlns, "canvas");
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -88,26 +88,26 @@ DebuggerView.Stackframes = {
    *
    * @param string aState
    *        Either "paused" or "attached".
    */
   updateState: function DVF_updateState(aState) {
     let resume = document.getElementById("resume");
     let status = document.getElementById("status");
 
-    // if we're paused, show a pause label and disable the resume button
+    // If we're paused, show a pause label and a resume label on the button.
     if (aState === "paused") {
       status.textContent = DebuggerView.getStr("pausedState");
-      resume.disabled = false;
+      resume.label = DebuggerView.getStr("resumeLabel");
     } else if (aState === "attached") {
-      // if we're attached, do the opposite
+      // If we're attached, do the opposite.
       status.textContent = DebuggerView.getStr("runningState");
-      resume.disabled = true;
+      resume.label = DebuggerView.getStr("pauseLabel");
     } else {
-      // no valid state parameter
+      // No valid state parameter.
       status.textContent = "";
     }
   },
 
   /**
    * Sets the onClick listener for the stackframes container.
    *
    * @param function aHandler
@@ -267,20 +267,24 @@ DebuggerView.Stackframes = {
     let root = document.documentElement;
     let debuggerClose = document.createEvent("Events");
 
     debuggerClose.initEvent("DebuggerClose", true, false);
     root.dispatchEvent(debuggerClose);
   },
 
   /**
-   * Listener handling the resume button click event.
+   * Listener handling the pause/resume button click event.
    */
   _onResumeButtonClick: function DVF__onResumeButtonClick() {
-    ThreadState.activeThread.resume();
+    if (ThreadState.activeThread.paused) {
+      ThreadState.activeThread.resume();
+    } else {
+      ThreadState.activeThread.interrupt();
+    }
   },
 
   /**
    * Specifies if the active thread has more frames which need to be loaded.
    */
   _dirty: false,
 
   /**
@@ -1088,16 +1092,27 @@ DebuggerView.Scripts = {
 
     let script = this._scripts.appendItem(aScriptNameText || aUrl, aUrl);
     script.setUserData("sourceScript", aSource, null);
     this._scripts.selectedItem = script;
     return script;
   },
 
   /**
+   * Returns the list of URIs for scripts in the page.
+   */
+  scriptLocations: function DVS_scriptLocations() {
+    let locations = [];
+    for (let i = 0; i < this._scripts.itemCount; i++) {
+      locations.push(this._scripts.getItemAtIndex(i).value);
+    }
+    return locations;
+  },
+
+  /**
    * The cached click listener for the scripts container.
    */
   _onScriptsChange: null,
 
   /**
    * The cached scripts container.
    */
   _scripts: null,
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -48,17 +48,17 @@
 <xul:window xmlns="http://www.w3.org/1999/xhtml"
             xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
     <xul:script type="text/javascript" src="debugger.js"/>
     <xul:script type="text/javascript" src="debugger-view.js"/>
 
     <div id="body" class="vbox flex">
         <xul:toolbar id="dbg-toolbar">
             <xul:button id="close">&debuggerUI.closeButton;</xul:button>
-            <xul:button id="resume">&debuggerUI.resumeButton;</xul:button>
+            <xul:button id="resume"/>
             <xul:menulist id="scripts"/>
         </xul:toolbar>
         <div id="dbg-content" class="hbox flex">
             <div id="stack" class="vbox">
                 <div class="title unselectable">&debuggerUI.stackTitle;</div>
                 <div id="stackframes" class="vbox flex"></div>
             </div>
             <div id="script" class="vbox flex">
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -64,16 +64,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_dbg_propertyview-08.js \
 	browser_dbg_panesize.js \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_location-changes.js \
 	browser_dbg_script-switching.js \
+	browser_dbg_pause-resume.js \
 	head.js \
 	$(NULL)
 
 _BROWSER_TEST_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_pause-resume.js
@@ -0,0 +1,74 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+
+function test() {
+  debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.debuggerWindow;
+
+    testPause();
+  });
+}
+
+function testPause() {
+  is(gDebugger.StackFrames.activeThread.paused, false,
+    "Should be running after debug_tab_pane.");
+
+  let button = gDebugger.document.getElementById("resume");
+  is(button.label, gDebugger.DebuggerView.getStr("pauseLabel"),
+    "Button label should be pause when running.");
+
+  gPane.activeThread.addOneTimeListener("paused", function() {
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      let frames = gDebugger.DebuggerView.Stackframes._frames;
+      let childNodes = frames.childNodes;
+
+      is(gDebugger.StackFrames.activeThread.paused, true,
+        "Should be paused after an interrupt request.");
+
+      is(button.label, gDebugger.DebuggerView.getStr("resumeLabel"),
+        "Button label should be resume when paused.");
+
+      is(frames.querySelectorAll(".dbg-stackframe").length, 0,
+        "Should have no frames when paused in the main loop.");
+
+      testResume();
+    }}, 0);
+  });
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    gDebugger.document.getElementById("resume"),
+    gDebugger);
+}
+
+function testResume() {
+  gPane.activeThread.addOneTimeListener("resumed", function() {
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      is(gDebugger.StackFrames.activeThread.paused, false,
+        "Should be paused after an interrupt request.");
+
+      let button = gDebugger.document.getElementById("resume");
+      is(button.label, gDebugger.DebuggerView.getStr("pauseLabel"),
+        "Button label should be pause when running.");
+
+      removeTab(gTab);
+      finish();
+    }}, 0);
+  });
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    gDebugger.document.getElementById("resume"),
+    gDebugger);
+}
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
@@ -50,26 +50,28 @@ function testFrameParameters()
         "Should have the right property value for 'this'.");
 
       // Expand the __proto__ and arguments tree nodes. This causes their
       // properties to be retrieved and displayed.
       localNodes[0].expand();
       localNodes[1].expand();
 
       // Poll every few milliseconds until the properties are retrieved.
+      // It's important to set the timer in the chrome window, because the
+      // content window timers are disabled while the debuggee is paused.
       let count = 0;
-      let intervalID = content.setInterval(function(){
+      let intervalID = window.setInterval(function(){
         if (++count > 50) {
           ok(false, "Timed out while polling for the properties.");
           resumeAndFinish();
         }
         if (!localNodes[0].fetched || !localNodes[1].fetched) {
           return;
         }
-        content.clearInterval(intervalID);
+        window.clearInterval(intervalID);
         is(localNodes[0].querySelector(".property > .title > .key")
                         .textContent, "__proto__ ",
           "Should have the right property name for __proto__.");
 
         ok(localNodes[0].querySelector(".property > .title > .value")
                         .textContent.search(/object/) != -1,
           "__proto__ should be an object.");
 
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mihai Sucan <mihai.sucan@gmail.com> (original author)
  *   Kenny Heaton <kennyheaton@gmail.com>
+ *   Spyros Livathinos <livathinos.spyros@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -70,16 +71,18 @@ const ORION_THEMES = {
 /**
  * Known editor events you can listen for. This object maps SourceEditor.EVENTS
  * to Orion events.
  */
 const ORION_EVENTS = {
   ContextMenu: "ContextMenu",
   TextChanged: "ModelChanged",
   Selection: "Selection",
+  Focus: "Focus",
+  Blur: "Blur",
 };
 
 /**
  * Known Orion annotation types.
  */
 const ORION_ANNOTATION_TYPES = {
   currentBracket: "orion.annotation.currentBracket",
   matchingBracket: "orion.annotation.matchingBracket",
--- a/browser/devtools/sourceeditor/source-editor.jsm
+++ b/browser/devtools/sourceeditor/source-editor.jsm
@@ -16,16 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Mihai Sucan <mihai.sucan@gmail.com> (original author)
+ *   Spyros Livathinos <livathinos.spyros@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -145,16 +146,26 @@ SourceEditor.EVENTS = {
   /**
    * The Selection event is fired when the editor selection changes. The event
    * object properties:
    *   - oldValue - the old selection range.
    *   - newValue - the new selection range.
    * Both ranges are objects which hold two properties: start and end.
    */
   SELECTION: "Selection",
+
+  /**
+   * The focus event is fired when the editor is focused.
+   */
+  FOCUS: "Focus",
+
+  /**
+   * The blur event is fired when the editor goes out of focus.
+   */
+  BLUR: "Blur",
 };
 
 /**
  * Extend a destination object with properties from a source object.
  *
  * @param object aDestination
  * @param object aSource
  */
--- a/browser/devtools/sourceeditor/test/Makefile.in
+++ b/browser/devtools/sourceeditor/test/Makefile.in
@@ -49,12 +49,13 @@ include $(topsrcdir)/config/rules.mk
 		browser_bug684862_paste_html.js \
 		browser_bug687573_vscroll.js \
 		browser_bug687568_pagescroll.js \
 		browser_bug687580_drag_and_drop.js \
 		browser_bug684546_reset_undo.js \
 		browser_bug695035_middle_click_paste.js \
 		browser_bug687160_line_api.js \
 		browser_bug650345_find.js \
+		browser_bug703692_focus_blur.js \
 		head.js \
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/sourceeditor/test/browser_bug703692_focus_blur.js
@@ -0,0 +1,71 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let tempScope = {};
+Cu.import("resource:///modules/source-editor.jsm", tempScope);
+let SourceEditor = tempScope.SourceEditor;
+
+let testWin;
+let editor;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
+    "<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
+    " title='Test for bug 703692' width='600' height='500'><hbox flex='1'/></window>";
+  const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
+
+  testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
+  testWin.addEventListener("load", function onWindowLoad() {
+    testWin.removeEventListener("load", onWindowLoad, false);
+    waitForFocus(initEditor, testWin);
+  }, false);
+}
+
+function initEditor()
+{
+  let hbox = testWin.document.querySelector("hbox");
+
+  editor = new SourceEditor();
+  editor.init(hbox, {}, editorLoaded);
+}
+
+function editorLoaded()
+{
+  let focusHandler = function(aEvent) {
+    editor.removeEventListener(SourceEditor.EVENTS.FOCUS, focusHandler);
+    editor.addEventListener(SourceEditor.EVENTS.BLUR, blurHandler);
+
+    ok(aEvent, "Focus event fired");
+    window.focus();
+  };
+
+  let blurHandler = function(aEvent) {
+    editor.removeEventListener(SourceEditor.EVENTS.BLUR, blurHandler);
+
+    ok(aEvent, "Blur event fired");
+    executeSoon(testEnd);
+  }
+
+  editor.addEventListener(SourceEditor.EVENTS.FOCUS, focusHandler);
+
+  editor.focus();
+}
+
+function testEnd()
+{
+  if (editor) {
+    editor.destroy();
+  }
+  if (testWin) {
+    testWin.close();
+  }
+  testWin = editor = null;
+
+  waitForFocus(finish, window);
+}
--- a/browser/devtools/webconsole/GcliCommands.jsm
+++ b/browser/devtools/webconsole/GcliCommands.jsm
@@ -120,8 +120,144 @@ gcli.addCommand({
       manual: gcli.lookup("inspectNodeManual")
     }
   ],
   exec: function Command_inspect(args, context) {
     let document = context.environment.chromeDocument;
     document.defaultView.InspectorUI.openInspectorUI(args.node);
   }
 });
+
+let breakpoints = [];
+
+/**
+ * 'break' command
+ */
+gcli.addCommand({
+  name: "break",
+  description: gcli.lookup("breakDesc"),
+  manual: gcli.lookup("breakManual")
+});
+
+
+/**
+ * 'break list' command
+ */
+gcli.addCommand({
+  name: "break list",
+  description: gcli.lookup("breaklistDesc"),
+  returnType: "html",
+  exec: function(args, context) {
+    if (breakpoints.length === 0) {
+      return gcli.lookup("breaklistNone");
+    }
+
+    let reply = gcli.lookup("breaklistIntro");
+    reply += "<ol>";
+    breakpoints.forEach(function(breakpoint) {
+      let text = gcli.lookupFormat("breaklistLineEntry",
+                                   [breakpoint.file, breakpoint.line]);
+      reply += "<li>" + text + "</li>";
+    });
+    reply += "</ol>";
+    return reply;
+  }
+});
+
+
+/**
+ * 'break add' command
+ */
+gcli.addCommand({
+  name: "break add",
+  description: gcli.lookup("breakaddDesc"),
+  manual: gcli.lookup("breakaddManual")
+});
+
+/**
+ * 'break add line' command
+ */
+gcli.addCommand({
+  name: "break add line",
+  description: gcli.lookup("breakaddlineDesc"),
+  params: [
+    {
+      name: "file",
+      type: {
+        name: "selection",
+        data: function() {
+          let win = HUDService.currentContext();
+          let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
+          let files = [];
+          if (dbg) {
+            let scriptsView = dbg.frame.contentWindow.DebuggerView.Scripts;
+            for each (let script in scriptsView.scriptLocations()) {
+              files.push(script);
+            }
+          }
+          return files;
+        }
+      },
+      description: gcli.lookup("breakaddlineFileDesc")
+    },
+    {
+      name: "line",
+      type: { name: "number", min: 1, step: 10 },
+      description: gcli.lookup("breakaddlineLineDesc")
+    }
+  ],
+  returnType: "html",
+  exec: function(args, context) {
+    args.type = "line";
+    let win = HUDService.currentContext();
+    let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
+    if (!dbg) {
+      return gcli.lookup("breakaddDebuggerStopped");
+    }
+    var promise = context.createPromise();
+    let position = { url: args.file, line: args.line };
+    dbg.activeThread.setBreakpoint(position, function(aResponse, aBpClient) {
+      if (aResponse.error) {
+        promise.resolve(gcli.lookupFormat("breakaddFailed",
+                        [ aResponse.error ]));
+        return;
+      }
+      args.client = aBpClient;
+      breakpoints.push(args);
+      promise.resolve(gcli.lookup("breakaddAdded"));
+    });
+    return promise;
+  }
+});
+
+
+/**
+ * 'break del' command
+ */
+gcli.addCommand({
+  name: "break del",
+  description: gcli.lookup("breakdelDesc"),
+  params: [
+    {
+      name: "breakid",
+      type: {
+        name: "number",
+        min: 0,
+        max: function() { return breakpoints.length - 1; }
+      },
+      description: gcli.lookup("breakdelBreakidDesc")
+    }
+  ],
+  returnType: "html",
+  exec: function(args, context) {
+    let breakpoint = breakpoints.splice(args.breakid, 1)[0];
+    var promise = context.createPromise();
+    try {
+      breakpoint.client.remove(function(aResponse) {
+                                 promise.resolve(gcli.lookup("breakdelRemoved"));
+                               });
+    } catch (ex) {
+      // If the debugger has been closed already, don't scare the user.
+      promise.resolve(gcli.lookup("breakdelRemoved"));
+    }
+    return promise;
+  }
+});
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -149,16 +149,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_gcli_inspect.js \
 	browser_gcli_integrate.js \
 	browser_gcli_require.js \
 	browser_gcli_web.js \
 	browser_webconsole_bug_658368_time_methods.js \
 	browser_webconsole_bug_622303_persistent_filters.js \
 	browser_webconsole_window_zombie.js \
 	browser_cached_messages.js \
+	browser_gcli_break.js \
 	head.js \
 	$(NULL)
 
 _BROWSER_TEST_PAGES = \
 	test-console.html \
 	test-network.html \
 	test-network-request.html \
 	test-mutation.html \
@@ -223,15 +224,16 @@ include $(topsrcdir)/config/rules.mk
 	test-bug-632275-getters.html \
 	test-bug-646025-console-file-location.html \
 	test-bug-678816-content.js \
 	test-file-location.js \
 	browser_gcli_inspect.html \
 	test-bug-658368-time-methods.html \
 	test-webconsole-error-observer.html \
 	test-for-of.html \
+	browser_gcli_break.html \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 
 libs:: $(_BROWSER_TEST_PAGES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_gcli_break.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+	<head>
+		<title>Browser GCLI break command test</title>
+    <!-- Any copyright is dedicated to the Public Domain.
+         http://creativecommons.org/publicdomain/zero/1.0/ -->
+    <script type="text/javascript">
+      function firstCall() {
+        eval("window.line0 = Error().lineNumber; secondCall();");
+      }
+      function secondCall() {
+        eval("debugger;");
+      }
+    </script>
+	</head>
+	<body>
+	</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_gcli_break.js
@@ -0,0 +1,104 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// For more information on GCLI see:
+// - https://github.com/mozilla/gcli/blob/master/docs/index.md
+// - https://wiki.mozilla.org/DevTools/Features/GCLI
+
+// Tests that the break command works as it should
+
+let tempScope = {};
+Components.utils.import("resource:///modules/gcli.jsm", tempScope);
+let gcli = tempScope.gcli;
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser_gcli_break.html";
+registerCleanupFunction(function() {
+  gcliterm = undefined;
+  requisition = undefined;
+
+  Services.prefs.clearUserPref("devtools.gcli.enable");
+});
+
+function test() {
+  Services.prefs.setBoolPref("devtools.gcli.enable", true);
+  addTab(TEST_URI);
+  browser.addEventListener("DOMContentLoaded", onLoad, false);
+}
+
+let gcliterm;
+let requisition;
+
+function onLoad() {
+  browser.removeEventListener("DOMContentLoaded", onLoad, false);
+
+  try {
+    openConsole();
+
+    let hud = HUDService.getHudByWindow(content);
+    gcliterm = hud.gcliterm;
+    requisition = gcliterm.opts.requisition;
+
+    testSetup();
+    testCreateCommands();
+  }
+  catch (ex) {
+    ok(false, "Caught exception: " + ex)
+    gcli._internal.console.error("Test Failure", ex);
+    closeConsole();
+    finishTest();
+  }
+}
+
+function testSetup() {
+  ok(gcliterm, "We have a GCLI term");
+  ok(requisition, "We have a Requisition");
+}
+
+function testCreateCommands() {
+  type("brea");
+  is(gcliterm.completeNode.textContent, " break", "Completion for 'brea'");
+  is(requisition.getStatus().toString(), "ERROR", "brea is ERROR");
+
+  type("break");
+  is(requisition.getStatus().toString(), "ERROR", "break is ERROR");
+
+  type("break add");
+  is(requisition.getStatus().toString(), "ERROR", "break add is ERROR");
+
+  type("break add line");
+  is(requisition.getStatus().toString(), "ERROR", "break add line is ERROR");
+
+  let pane = DebuggerUI.toggleDebugger();
+  pane.onConnected = function test_onConnected(aPane) {
+    // Wait for the initial resume.
+    aPane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
+      delete aPane.onConnected;
+      aPane.debuggerWindow.gClient.activeThread.addOneTimeListener("scriptsadded", function() {
+        type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0);
+        is(requisition.getStatus().toString(), "VALID", "break add line is VALID");
+        requisition.exec();
+
+        type("break list");
+        is(requisition.getStatus().toString(), "VALID", "break list is VALID");
+        requisition.exec();
+
+        aPane.debuggerWindow.gClient.activeThread.resume(function() {
+          type("break del 0");
+          is(requisition.getStatus().toString(), "VALID", "break del 0 is VALID");
+          requisition.exec();
+
+          closeConsole();
+          finishTest();
+        });
+      });
+      // Trigger newScript notifications using eval.
+      content.wrappedJSObject.firstCall();
+    });
+  }
+}
+
+function type(command) {
+  gcliterm.inputNode.value = command.slice(0, -1);
+  gcliterm.inputNode.focus();
+  EventUtils.synthesizeKey(command.slice(-1), {});
+}
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -14,22 +14,16 @@
 <!-- LOCALIZATION NOTE (debuggerMenu.commandkey): This is the command key that
   -  launches the debugger UI. Do not translate this one! -->
 <!ENTITY debuggerMenu.commandkey     "S">
 
 <!-- LOCALIZATION NOTE (debuggerUI.closeButton): This is the label for the
   -  button that closes the debugger UI. -->
 <!ENTITY debuggerUI.closeButton      "Close">
 
-<!-- LOCALIZATION NOTE (debuggerUI.resumeButton): This is the label for the
-  -  button that resumes the debugger, after it has reached a paused state. In
-  -  a paused state the debugger can be used to inspect stack frames, local,
-  -  variables etc. -->
-<!ENTITY debuggerUI.resumeButton     "Resume">
-
 <!-- LOCALIZATION NOTE (debuggerUI.stackTitle): This is the label for the
   -  widget that displays the call stack frames in the debugger. -->
 <!ENTITY debuggerUI.stackTitle       "Call stack">
 
 <!-- LOCALIZATION NOTE (debuggerUI.scriptTitle): This is the label for the
   -  widget that displays the source code for the script that is currently
   -  being inspected in the debugger. -->
 <!ENTITY debuggerUI.scriptTitle      "Script">
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.properties
@@ -1,16 +1,24 @@
 # LOCALIZATION NOTE These strings are used inside the Script Debugger
 # which is available from the Web Developer sub-menu -> 'Script Debugger'.
 # The correct localization of this file might be to keep it in
 # English, or another language commonly spoken among web developers.
 # You want to make that choice consistent across the developer tools.
 # A good criteria is the language in which you'd find the best
 # documentation on web development on the web.
 
+# LOCALIZATION NOTE (pauseLabel): The label that is displayed on the pause
+# button when the debugger is in a running state.
+pauseLabel=Pause
+
+# LOCALIZATION NOTE (resumeLabel): The label that is displayed on the pause
+# button when the debugger is in a paused state.
+resumeLabel=Resume
+
 # LOCALIZATION NOTE (pausedState): The label that is displayed when the
 # debugger is in a paused state.
 pausedState=Paused
 
 # LOCALIZATION NOTE (runningState): The label that is displayed when the
 # debugger is in a running state.
 runningState=Running
 
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -51,12 +51,81 @@ inspectManual=Investigate the dimensions
 # when the user is using this command.
 inspectNodeDesc=CSS selector
 
 # LOCALIZATION NOTE (inspectNodeManual) A fuller description of the 'node'
 # parameter to the 'inspect' command, displayed when the user asks for help
 # on what it does.
 inspectNodeManual=A CSS selector for use with Document.querySelector which identifies a single element
 
+# LOCALIZATION NOTE (breakDesc) A very short string used to describe the
+# function of the break command.
+breakDesc=Manage breakpoints
+
+# LOCALIZATION NOTE (breakManual) A longer description describing the
+# set of commands that control breakpoints.
+breakManual=Commands to list, add and remove breakpoints
+
+# LOCALIZATION NOTE (breaklistDesc) A very short string used to describe the
+# function of the 'break list' command.
+breaklistDesc=Display known breakpoints
+
+# LOCALIZATION NOTE (breaklistLineEntry) Used in the output of the 'break list'
+# command to display a single line breakpoint.
+# %1$S=script URL, %2$S=line number
+breaklistLineEntry=Line breakpoint at %1$S:%2$S
+
+# LOCALIZATION NOTE (breaklistNone) Used in the output of the 'break list'
+# command to explain that the list is empty.
+breaklistNone=No breakpoints set
+
+# LOCALIZATION NOTE (breaklistIntro) Used in the output of the 'break list'
+# command to preface the list contents.
+breaklistIntro=The following breakpoints are set:
+
+# LOCALIZATION NOTE (breakaddAdded) Used in the output of the 'break add'
+# command to explain that a breakpoint was added.
+breakaddAdded=Added breakpoint
+
+# LOCALIZATION NOTE (breakaddFailed) Used in the output of the 'break add'
+# command to explain that a breakpoint could not be added.
+breakaddFailed=Could not set breakpoint: %S
+
+# LOCALIZATION NOTE (breakaddDesc) A very short string used to describe the
+# function of the 'break add' command.
+breakaddDesc=Add a breakpoint
+
+# LOCALIZATION NOTE (breakaddManual) A longer description describing the
+# set of commands that are responsible for adding breakpoints.
+breakaddManual=Breakpoint types supported: line
+
+# LOCALIZATION NOTE (breakaddDebuggerStopped) Used in the output of the
+# 'break add' command to explain that the debugger must be opened first.
+breakaddDebuggerStopped=The debugger must be opened before setting breakpoints
+
+# LOCALIZATION NOTE (breakaddlineDesc) A very short string used to describe the
+# function of the 'break add line' command.
+breakaddlineDesc=Add a line breakpoint
+
+# LOCALIZATION NOTE (breakaddlineFileDesc) A very short string used to describe
+# the function of the file parameter in the 'break add line' command.
+breakaddlineFileDesc=JS file URI
+
+# LOCALIZATION NOTE (breakaddlineLineDesc) A very short string used to describe
+# the function of the line parameter in the 'break add line' command.
+breakaddlineLineDesc=Line number
+
+# LOCALIZATION NOTE (breakdelDesc) A very short string used to describe the
+# function of the 'break del' command.
+breakdelDesc=Remove a breakpoint
+
+# LOCALIZATION NOTE (breakdelBreakidDesc) A very short string used to describe
+# the function of the index parameter in the 'break del' command.
+breakdelBreakidDesc=Index of breakpoint
+
+# LOCALIZATION NOTE (breakdelRemoved) Used in the output of the 'break del'
+# command to explain that a breakpoint was removed.
+breakdelRemoved=Breakpoint removed
+
 # LOCALIZATION NOTE (consolecloseDesc) A very short description of the
 # 'console close' command. This string is designed to be shown in a menu
 # alongside the command name, which is why it should be as short as possible.
 consolecloseDesc=Close the console
--- a/browser/modules/NewTabUtils.jsm
+++ b/browser/modules/NewTabUtils.jsm
@@ -167,17 +167,17 @@ PrivateBrowsingStorage.prototype = {
   setItem: function PrivateBrowsingStorage_setItem(aKey, aValue) {
     this._data.set(aKey, aValue);
   },
 
   /**
    * Clears the storage and removes all values.
    */
   clear: function PrivateBrowsingStorage_clear() {
-    this._data.listkeys().forEach(function (akey) {
+    this._data.listkeys().forEach(function (aKey) {
       this._data.del(aKey);
     }, this);
   }
 };
 
 /**
  * Singleton that serves as a registry for all open 'New Tab Page's.
  */
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3416,17 +3416,16 @@ nsContentUtils::MaybeFireNodeRemoved(nsI
     nsEventDispatcher::Dispatch(aChild, nsnull, &mutation);
   }
 }
 
 PLDHashOperator
 ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry,
                    PRUint32 aNumber, void* aArg)
 {
-  PRUint32* gen = static_cast<PRUint32*>(aArg);
   EventListenerManagerMapEntry* entry =
     static_cast<EventListenerManagerMapEntry*>(aEntry);
   if (entry) {
     nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget());
     if (n && n->IsInDoc() &&
         nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) {
       entry->mListenerManager->UnmarkGrayJSListeners();
     }
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -79,16 +79,19 @@
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
 #include "nsStringBuffer.h"
 #include "mozilla/dom/Element.h"
 
+using namespace mozilla;
+using namespace mozilla::dom;
+
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
 
 enum nsRangeIterationDirection {
   kDirectionOut = -1,
   kDirectionIn = 1
 };
 
 class nsDocumentEncoder : public nsIDocumentEncoder
@@ -373,17 +376,17 @@ nsDocumentEncoder::SerializeNodeStart(ns
   }
 
   // Either there was no fixed-up node,
   // or the caller did fixup themselves and aNode is already fixed
   if (!node)
     node = aNode;
   
   if (node->IsElement()) {
-    mozilla::dom::Element* originalElement =
+    Element* originalElement =
       aOriginalNode && aOriginalNode->IsElement() ?
         aOriginalNode->AsElement() : nsnull;
     mSerializer->AppendElementStart(node->AsElement(),
                                     originalElement, aStr);
     return NS_OK;
   }
 
   switch (node->NodeType()) {
@@ -1790,32 +1793,22 @@ nsHTMLCopyEncoder::GetChildAt(nsIDOMNode
   resultNode = do_QueryInterface(content->GetChildAt(aOffset));
 
   return resultNode;
 }
 
 bool 
 nsHTMLCopyEncoder::IsMozBR(nsIDOMNode* aNode)
 {
-  nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
-  if (IsTag(content, nsGkAtoms::br))
-  {
-    nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(aNode);
-    if (elem)
-    {
-      nsAutoString typeAttrName(NS_LITERAL_STRING("type"));
-      nsAutoString typeAttrVal;
-      nsresult rv = elem->GetAttribute(typeAttrName, typeAttrVal);
-      ToLowerCase(typeAttrVal);
-      if (NS_SUCCEEDED(rv) && (typeAttrVal.EqualsLiteral("_moz")))
-        return true;
-    }
-    return false;
-  }
-  return false;
+  MOZ_ASSERT(aNode);
+  nsCOMPtr<Element> element = do_QueryInterface(aNode);
+  return element &&
+         element->IsHTML(nsGkAtoms::br) &&
+         element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
+                              NS_LITERAL_STRING("_moz"), eIgnoreCase);
 }
 
 nsresult 
 nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild,
                                    nsCOMPtr<nsIDOMNode> *outParent,
                                    PRInt32 *outOffset)
 {
   NS_ASSERTION((inChild && outParent && outOffset), "bad args");
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -601,22 +601,16 @@ nsDummyJavaPluginOwner::InvalidateRect(N
 
 NS_IMETHODIMP
 nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsDummyJavaPluginOwner::ForceRedraw()
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
 nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel)
 {
--- a/dom/plugins/base/nsIPluginInstanceOwner.idl
+++ b/dom/plugins/base/nsIPluginInstanceOwner.idl
@@ -44,17 +44,19 @@ interface nsIDocument;
 %{C++
 #include "npapi.h"
 #include "nsNPAPIPluginInstance.h"
 class nsPluginEvent;
 %}
 
 [ptr] native nsNPAPIPluginInstancePtr(nsNPAPIPluginInstance);
 
-[uuid(17E89C1F-AE62-448E-83D5-C33FA6E07A19)]
+// Do not make this interface scriptable, because the virtual functions in C++
+// blocks will make script call the wrong functions.
+[uuid(23bd0a76-a5dc-4a1d-be76-13d7a0dfd9ff)]
 interface nsIPluginInstanceOwner : nsISupports
 {
   /**
    * Let the owner know what its instance is
    */
   void setInstance(in nsNPAPIPluginInstancePtr aInstance);
 
   /**
@@ -112,21 +114,16 @@ interface nsIPluginInstanceOwner : nsISu
   void invalidateRect(in NPRectPtr aRect);
 
   /**
    * Invalidate the region
    */
   void invalidateRegion(in NPRegion aRegion);
 
   /**
-   * Force a redraw
-   */
-  void forceRedraw();
-
-  /**
    * Get NetscapeWindow, corresponds to NPNVnetscapeWindow
    */
   void getNetscapeWindow(in voidPtr aValue);
 
   /**
    * Show native context menu
    */
 %{C++
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -1303,32 +1303,16 @@ void NP_CALLBACK
   PluginDestructionGuard guard(inst);
 
   inst->InvalidateRegion((NPRegion)invalidRegion);
 }
 
 void NP_CALLBACK
 _forceredraw(NPP npp)
 {
-  if (!NS_IsMainThread()) {
-    NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_forceredraw called from the wrong thread\n"));
-    return;
-  }
-  NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_ForceDraw: npp=%p\n", (void*)npp));
-
-  if (!npp || !npp->ndata) {
-    NS_WARNING("_forceredraw: npp or npp->ndata == 0");
-    return;
-  }
-
-  nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
-
-  PluginDestructionGuard guard(inst);
-
-  inst->ForceRedraw();
 }
 
 NPObject* NP_CALLBACK
 _getwindowobject(NPP npp)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getwindowobject called from the wrong thread\n"));
     return nsnull;
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1345,30 +1345,16 @@ nsNPAPIPluginInstance::InvalidateRegion(
   GetOwner(getter_AddRefs(owner));
   if (!owner)
     return NS_ERROR_FAILURE;
 
   return owner->InvalidateRegion(invalidRegion);
 }
 
 nsresult
-nsNPAPIPluginInstance::ForceRedraw()
-{
-  if (RUNNING != mRunning)
-    return NS_OK;
-
-  nsCOMPtr<nsIPluginInstanceOwner> owner;
-  GetOwner(getter_AddRefs(owner));
-  if (!owner)
-    return NS_ERROR_FAILURE;
-
-  return owner->ForceRedraw();
-}
-
-nsresult
 nsNPAPIPluginInstance::GetMIMEType(const char* *result)
 {
   if (!mMIMEType)
     *result = "";
   else
     *result = mMIMEType;
 
   return NS_OK;
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -110,17 +110,16 @@ public:
   nsresult EndUpdateBackground(gfxContext* aContext, nsIntRect* aRect);
   nsresult IsTransparent(bool* isTransparent);
   nsresult GetFormValue(nsAString& aValue);
   nsresult PushPopupsEnabledState(bool aEnabled);
   nsresult PopPopupsEnabledState();
   nsresult GetPluginAPIVersion(PRUint16* version);
   nsresult InvalidateRect(NPRect *invalidRect);
   nsresult InvalidateRegion(NPRegion invalidRegion);
-  nsresult ForceRedraw();
   nsresult GetMIMEType(const char* *result);
   nsresult GetJSContext(JSContext* *outContext);
   nsresult GetOwner(nsIPluginInstanceOwner **aOwner);
   nsresult SetOwner(nsIPluginInstanceOwner *aOwner);
   nsresult ShowStatus(const char* message);
   nsresult InvalidateOwner();
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
   nsresult HandleGUIEvent(const nsGUIEvent& anEvent, bool* handled);
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -669,21 +669,16 @@ NS_IMETHODIMP nsPluginInstanceOwner::Inv
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-NS_IMETHODIMP nsPluginInstanceOwner::ForceRedraw()
-{
-  return NS_OK;
-}
-
 NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
 {
   if (!mObjectFrame) {
     NS_WARNING("plugin owner has no owner in getting doc's window handle");
     return NS_ERROR_FAILURE;
   }
   
 #if defined(XP_WIN) || defined(XP_OS2)
--- a/dom/system/b2g/Makefile.in
+++ b/dom/system/b2g/Makefile.in
@@ -1,17 +1,11 @@
-# ***** BEGIN LICENSE BLOCK *****
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/. */#
-#
-# Contributor(s):
-#   Ben Turner <bent.mozilla@gmail.com> (Original Author)
-#
-# ***** END LICENSE BLOCK *****
+# You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DEPTH            = ../../..
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
--- a/editor/libeditor/html/nsHTMLCSSUtils.cpp
+++ b/editor/libeditor/html/nsHTMLCSSUtils.cpp
@@ -313,26 +313,36 @@ nsHTMLCSSUtils::~nsHTMLCSSUtils()
 // by aProperty and/or aAttribute for the node aNode
 bool
 nsHTMLCSSUtils::IsCSSEditableProperty(nsIDOMNode * aNode,
                                       nsIAtom * aProperty,
                                       const nsAString * aAttribute)
 {
   NS_ASSERTION(aNode, "Shouldn't you pass aNode? - Bug 214025");
 
-  nsCOMPtr<nsIDOMNode> node = aNode;
+  nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
+  NS_ENSURE_TRUE(content, false);
+  return IsCSSEditableProperty(content, aProperty, aAttribute);
+}
+
+bool
+nsHTMLCSSUtils::IsCSSEditableProperty(nsIContent* aNode,
+                                      nsIAtom* aProperty,
+                                      const nsAString* aAttribute)
+{
+  MOZ_ASSERT(aNode);
+
+  nsIContent* content = aNode;
   // we need an element node here
-  if (mHTMLEditor->IsTextNode(aNode)) {
-    aNode->GetParentNode(getter_AddRefs(node));
+  if (content->NodeType() == nsIDOMNode::TEXT_NODE) {
+    content = content->GetParent();
+    NS_ENSURE_TRUE(content, false);
   }
-  nsCOMPtr<nsIContent> content = do_QueryInterface(node);
-  NS_ENSURE_TRUE(content, false);
 
   nsIAtom *tagName = content->Tag();
-  // brade: should the above use nsEditor::GetTag(aNode)?
   // brade: shouldn't some of the above go below the next block?
 
   // html inline styles B I TT U STRIKE and COLOR/FACE on FONT
   if (nsEditProperty::b == aProperty
       || nsEditProperty::i == aProperty
       || nsEditProperty::tt == aProperty
       || nsEditProperty::u == aProperty
       || nsEditProperty::strike == aProperty
@@ -528,16 +538,26 @@ nsHTMLCSSUtils::GetComputedProperty(nsID
   nsCOMPtr<nsIDOMWindow> window;
   nsresult res = GetDefaultViewCSS(aNode, getter_AddRefs(window));
   NS_ENSURE_SUCCESS(res, res);
 
   return GetCSSInlinePropertyBase(aNode, aProperty, aValue, window, COMPUTED_STYLE_TYPE);
 }
 
 nsresult
+nsHTMLCSSUtils::GetCSSInlinePropertyBase(nsINode* aNode, nsIAtom* aProperty,
+                                         nsAString& aValue,
+                                         nsIDOMWindow* aWindow,
+                                         PRUint8 aStyleType)
+{
+  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
+  return GetCSSInlinePropertyBase(node, aProperty, aValue, aWindow, aStyleType);
+}
+
+nsresult
 nsHTMLCSSUtils::GetCSSInlinePropertyBase(nsIDOMNode *aNode, nsIAtom *aProperty,
                                          nsAString& aValue,
                                          nsIDOMWindow* aWindow,
                                          PRUint8 aStyleType)
 {
   aValue.Truncate();
   NS_ENSURE_TRUE(aProperty, NS_ERROR_NULL_POINTER);
 
@@ -575,68 +595,52 @@ nsHTMLCSSUtils::GetCSSInlinePropertyBase
       break;
   }
   return NS_OK;
 }
 
 nsresult
 nsHTMLCSSUtils::GetDefaultViewCSS(nsIDOMNode *aNode, nsIDOMWindow **aViewCSS)
 {
-  nsCOMPtr<nsIDOMElement> element = GetElementContainerOrSelf(aNode);
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
+  return GetDefaultViewCSS(node, aViewCSS);
+}
+
+nsresult
+nsHTMLCSSUtils::GetDefaultViewCSS(nsINode* aNode, nsIDOMWindow** aViewCSS)
+{
+  MOZ_ASSERT(aNode);
+  dom::Element* element = GetElementContainerOrSelf(aNode);
   NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
 
-  // TODO: move this initialization to the top of the function
-  *aViewCSS = nsnull;
-  if (!element) {
-    return NS_OK;
-  }
-  // find the owner document
-  nsCOMPtr<nsIDOMDocument> doc;
-  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(element);
-  nsresult res = node->GetOwnerDocument(getter_AddRefs(doc));
-  NS_ENSURE_SUCCESS(res, res);
-  if (!doc) {
-    return NS_OK;
-  }
-  nsCOMPtr<nsIDOMWindow> window;
-  res = doc->GetDefaultView(getter_AddRefs(window));
-  NS_ENSURE_SUCCESS(res, res);
+  nsCOMPtr<nsIDOMWindow> window = element->OwnerDoc()->GetWindow();
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   window.forget(aViewCSS);
   return NS_OK;
 }
 
 // remove the CSS style "aProperty : aPropertyValue" and possibly remove the whole node
 // if it is a span and if its only attribute is _moz_dirty
 nsresult
 nsHTMLCSSUtils::RemoveCSSInlineStyle(nsIDOMNode *aNode, nsIAtom *aProperty, const nsAString & aPropertyValue)
 {
   nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(aNode);
 
   // remove the property from the style attribute
   nsresult res = RemoveCSSProperty(elem, aProperty, aPropertyValue, false);
   NS_ENSURE_SUCCESS(res, res);
 
-  if (nsEditor::NodeIsType(aNode, nsEditProperty::span)) {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
-    PRUint32 attrCount = content->GetAttrCount();
+  nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
+  if (!element || !element->IsHTML(nsGkAtoms::span) ||
+      nsHTMLEditor::HasAttributes(element)) {
+    return NS_OK;
+  }
 
-    if (0 == attrCount) {
-      // no more attributes on this span, let's remove the element
-      res = mHTMLEditor->RemoveContainer(aNode);
-      NS_ENSURE_SUCCESS(res, res);
-    }
-    else if (1 == attrCount) {
-      // incredible hack in case the only remaining attribute is a _moz_dirty...
-      if (content->GetAttrNameAt(0)->Equals(nsEditProperty::mozdirty)) {
-        res = mHTMLEditor->RemoveContainer(aNode);
-        NS_ENSURE_SUCCESS(res, res);
-      }
-    }
-  }
-  return NS_OK;
+  return mHTMLEditor->RemoveContainer(aNode);
 }
 
 // Answers true is the property can be removed by setting a "none" CSS value
 // on a node
 bool
 nsHTMLCSSUtils::IsCSSInvertable(nsIAtom *aProperty, const nsAString *aAttribute)
 {
   return bool(nsEditProperty::b == aProperty);
@@ -834,31 +838,26 @@ nsHTMLCSSUtils::BuildCSSDeclarations(nsT
     index++;
     cssProperty = aEquivTable[index].cssProperty;
   }
 }
 
 // Populate cssPropertyArray and cssValueArray with the declarations equivalent
 // to aHTMLProperty/aAttribute/aValue for the node aNode
 void
-nsHTMLCSSUtils::GenerateCSSDeclarationsFromHTMLStyle(nsIDOMNode * aNode,
-                                                     nsIAtom *aHTMLProperty,
-                                                     const nsAString * aAttribute,
-                                                     const nsAString * aValue,
-                                                     nsTArray<nsIAtom*> & cssPropertyArray,
-                                                     nsTArray<nsString> & cssValueArray,
+nsHTMLCSSUtils::GenerateCSSDeclarationsFromHTMLStyle(dom::Element* aElement,
+                                                     nsIAtom* aHTMLProperty,
+                                                     const nsAString* aAttribute,
+                                                     const nsAString* aValue,
+                                                     nsTArray<nsIAtom*>& cssPropertyArray,
+                                                     nsTArray<nsString>& cssValueArray,
                                                      bool aGetOrRemoveRequest)
 {
-  nsCOMPtr<nsIDOMNode> node = aNode;
-  if (mHTMLEditor->IsTextNode(aNode)) {
-    aNode->GetParentNode(getter_AddRefs(node));
-  }
-  if (!node) return;
-
-  nsIAtom *tagName = nsEditor::GetTag(node);
+  MOZ_ASSERT(aElement);
+  nsIAtom* tagName = aElement->Tag();
 
   if (nsEditProperty::b == aHTMLProperty) {
     BuildCSSDeclarations(cssPropertyArray, cssValueArray, boldEquivTable, aValue, aGetOrRemoveRequest);
   }
   else if (nsEditProperty::i == aHTMLProperty) {
     BuildCSSDeclarations(cssPropertyArray, cssValueArray, italicEquivTable, aValue, aGetOrRemoveRequest);
   }
   else if (nsEditProperty::u == aHTMLProperty) {
@@ -933,118 +932,123 @@ nsHTMLCSSUtils::GenerateCSSDeclarationsF
 nsresult
 nsHTMLCSSUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode * aNode,
                                             nsIAtom *aHTMLProperty,
                                             const nsAString *aAttribute,
                                             const nsAString *aValue,
                                             PRInt32 * aCount,
                                             bool aSuppressTransaction)
 {
-  nsCOMPtr<nsIDOMElement> theElement = do_QueryInterface(aNode);
-  nsresult res = NS_OK;
+  nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
   *aCount = 0;
-  if (theElement && IsCSSEditableProperty(aNode, aHTMLProperty, aAttribute)) {
-    // we can apply the styles only if the node is an element and if we have
-    // an equivalence for the requested HTML style in this implementation
+  if (!element || !IsCSSEditableProperty(element, aHTMLProperty, aAttribute)) {
+    return NS_OK;
+  }
+
+  // we can apply the styles only if the node is an element and if we have
+  // an equivalence for the requested HTML style in this implementation
 
-    // Find the CSS equivalence to the HTML style
-    nsTArray<nsIAtom*> cssPropertyArray;
-    nsTArray<nsString> cssValueArray;
-    GenerateCSSDeclarationsFromHTMLStyle(aNode, aHTMLProperty, aAttribute, aValue,
-                                         cssPropertyArray, cssValueArray, false);
+  // Find the CSS equivalence to the HTML style
+  nsTArray<nsIAtom*> cssPropertyArray;
+  nsTArray<nsString> cssValueArray;
+  GenerateCSSDeclarationsFromHTMLStyle(element, aHTMLProperty, aAttribute,
+                                       aValue, cssPropertyArray, cssValueArray,
+                                       false);
 
-    // set the individual CSS inline styles
-    *aCount = cssPropertyArray.Length();
-    PRInt32 index;
-    for (index = 0; index < *aCount; index++) {
-      nsCOMPtr<nsIDOMElement> theElement = do_QueryInterface(aNode);
-      res = SetCSSProperty(theElement, cssPropertyArray[index],
-                           cssValueArray[index], aSuppressTransaction);
-      NS_ENSURE_SUCCESS(res, res);
-    }
+  nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(element);
+  // set the individual CSS inline styles
+  *aCount = cssPropertyArray.Length();
+  for (PRInt32 index = 0; index < *aCount; index++) {
+    nsresult res = SetCSSProperty(domElement, cssPropertyArray[index],
+                                  cssValueArray[index], aSuppressTransaction);
+    NS_ENSURE_SUCCESS(res, res);
   }
   return NS_OK;
 }
 
 // Remove from aNode the CSS inline style equivalent to HTMLProperty/aAttribute/aValue for the node
 nsresult
 nsHTMLCSSUtils::RemoveCSSEquivalentToHTMLStyle(nsIDOMNode * aNode,
                                                nsIAtom *aHTMLProperty,
                                                const nsAString *aAttribute,
                                                const nsAString *aValue,
                                                bool aSuppressTransaction)
 {
-  nsCOMPtr<nsIDOMElement> theElement = do_QueryInterface(aNode);
-  nsresult res = NS_OK;
-  PRInt32 count = 0;
-  if (theElement && IsCSSEditableProperty(aNode, aHTMLProperty, aAttribute)) {
-    // we can apply the styles only if the node is an element and if we have
-    // an equivalence for the requested HTML style in this implementation
+  nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
+  if (!element || !IsCSSEditableProperty(element, aHTMLProperty, aAttribute)) {
+    return NS_OK;
+  }
+
+  // we can apply the styles only if the node is an element and if we have
+  // an equivalence for the requested HTML style in this implementation
 
-    // Find the CSS equivalence to the HTML style
-    nsTArray<nsIAtom*> cssPropertyArray;
-    nsTArray<nsString> cssValueArray;
-    GenerateCSSDeclarationsFromHTMLStyle(aNode, aHTMLProperty, aAttribute, aValue,
-                                         cssPropertyArray, cssValueArray, true);
+  // Find the CSS equivalence to the HTML style
+  nsTArray<nsIAtom*> cssPropertyArray;
+  nsTArray<nsString> cssValueArray;
+  GenerateCSSDeclarationsFromHTMLStyle(element, aHTMLProperty, aAttribute,
+                                       aValue, cssPropertyArray, cssValueArray,
+                                       true);
 
-    // remove the individual CSS inline styles
-    count = cssPropertyArray.Length();
-    PRInt32 index;
-    for (index = 0; index < count; index++) {
-      res = RemoveCSSProperty(theElement,
-                              cssPropertyArray[index],
-                              cssValueArray[index],
-                              aSuppressTransaction);
-      NS_ENSURE_SUCCESS(res, res);
-    }
+  nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(element);
+  // remove the individual CSS inline styles
+  PRInt32 count = cssPropertyArray.Length();
+  for (PRInt32 index = 0; index < count; index++) {
+    nsresult res = RemoveCSSProperty(domElement,
+                                     cssPropertyArray[index],
+                                     cssValueArray[index],
+                                     aSuppressTransaction);
+    NS_ENSURE_SUCCESS(res, res);
   }
   return NS_OK;
 }
 
 // returns in aValueString the list of values for the CSS equivalences to
 // the HTML style aHTMLProperty/aAttribute/aValueString for the node aNode;
 // the value of aStyleType controls the styles we retrieve : specified or
 // computed.
 nsresult
-nsHTMLCSSUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode * aNode,
+nsHTMLCSSUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
                                                      nsIAtom *aHTMLProperty,
                                                      const nsAString *aAttribute,
                                                      nsAString & aValueString,
                                                      PRUint8 aStyleType)
 {
   aValueString.Truncate();
-  nsCOMPtr<nsIDOMElement> theElement = GetElementContainerOrSelf(aNode);
+  nsCOMPtr<dom::Element> theElement = GetElementContainerOrSelf(aNode);
   NS_ENSURE_TRUE(theElement, NS_ERROR_NULL_POINTER);
 
-  if (theElement && IsCSSEditableProperty(theElement, aHTMLProperty, aAttribute)) {
-    // Yes, the requested HTML style has a CSS equivalence in this implementation
-    // Retrieve the default ViewCSS if we are asked for computed styles
-    nsCOMPtr<nsIDOMWindow> window;
-    if (COMPUTED_STYLE_TYPE == aStyleType) {
-      nsresult res = GetDefaultViewCSS(theElement, getter_AddRefs(window));
-      NS_ENSURE_SUCCESS(res, res);
+  if (!theElement || !IsCSSEditableProperty(theElement, aHTMLProperty, aAttribute)) {
+    return NS_OK;
+  }
+
+  // Yes, the requested HTML style has a CSS equivalence in this implementation
+  // Retrieve the default ViewCSS if we are asked for computed styles
+  nsCOMPtr<nsIDOMWindow> window;
+  if (COMPUTED_STYLE_TYPE == aStyleType) {
+    nsresult res = GetDefaultViewCSS(theElement, getter_AddRefs(window));
+    NS_ENSURE_SUCCESS(res, res);
+  }
+  nsTArray<nsIAtom*> cssPropertyArray;
+  nsTArray<nsString> cssValueArray;
+  // get the CSS equivalence with last param true indicating we want only the
+  // "gettable" properties
+  GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute, nsnull,
+                                       cssPropertyArray, cssValueArray, true);
+  PRInt32 count = cssPropertyArray.Length();
+  for (PRInt32 index = 0; index < count; index++) {
+    nsAutoString valueString;
+    // retrieve the specified/computed value of the property
+    nsresult res = GetCSSInlinePropertyBase(theElement, cssPropertyArray[index],
+                                            valueString, window, aStyleType);
+    NS_ENSURE_SUCCESS(res, res);
+    // append the value to aValueString (possibly with a leading whitespace)
+    if (index) {
+      aValueString.Append(PRUnichar(' '));
     }
-    nsTArray<nsIAtom*> cssPropertyArray;
-    nsTArray<nsString> cssValueArray;
-    // get the CSS equivalence with last param true indicating we want only the
-    // "gettable" properties
-    GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute, nsnull,
-                                         cssPropertyArray, cssValueArray, true);
-    PRInt32 count = cssPropertyArray.Length();
-    PRInt32 index;
-    for (index = 0; index < count; index++) {
-      nsAutoString valueString;
-      // retrieve the specified/computed value of the property
-      nsresult res = GetCSSInlinePropertyBase(theElement, cssPropertyArray[index],
-                                              valueString, window, aStyleType);
-      NS_ENSURE_SUCCESS(res, res);
-      // append the value to aValueString (possibly with a leading whitespace)
-      if (index) aValueString.Append(PRUnichar(' '));
-      aValueString.Append(valueString);
-    }
+    aValueString.Append(valueString);
   }
   return NS_OK;
 }
 
 // Does the node aNode (or his parent if it is not an element node) carries
 // the CSS equivalent styles to the HTML style aHTMLProperty/aAttribute/
 // aValueString for this node ?
 // The value of aStyleType controls the styles we retrieve : specified or
@@ -1056,17 +1060,17 @@ nsHTMLCSSUtils::IsCSSEquivalentToHTMLInl
                                                     bool & aIsSet,
                                                     nsAString & valueString,
                                                     PRUint8 aStyleType)
 {
   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
 
   nsAutoString htmlValueString(valueString);
   aIsSet = false;
-  nsCOMPtr<nsIDOMNode> node = aNode;
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
   NS_NAMED_LITERAL_STRING(boldStr, "bold");
   do {
     valueString.Assign(htmlValueString);
     // get the value of the CSS equivalent styles
     nsresult res = GetCSSEquivalentToHTMLInlineStyleSet(node, aHTMLProperty, aHTMLAttribute,
                                                         valueString, aStyleType);
     NS_ENSURE_SUCCESS(res, res);
 
@@ -1195,21 +1199,17 @@ nsHTMLCSSUtils::IsCSSEquivalentToHTMLInl
                                  nsCaseInsensitiveStringComparator())) {
         aIsSet = true;
       }
     }
 
     if (nsEditProperty::u == aHTMLProperty || nsEditProperty::strike == aHTMLProperty) {
       // unfortunately, the value of the text-decoration property is not inherited.
       // that means that we have to look at ancestors of node to see if they are underlined
-      nsCOMPtr<nsIDOMNode> tmp;
-      res = node->GetParentNode(getter_AddRefs(tmp));
-      NS_ENSURE_SUCCESS(res, res);
-      nsCOMPtr<nsIDOMElement> element = do_QueryInterface(tmp);
-      node = element;  // set to null if it's not a dom element
+      node = node->GetElementParent();  // set to null if it's not a dom element
     }
   } while ((nsEditProperty::u == aHTMLProperty || nsEditProperty::strike == aHTMLProperty) &&
            !aIsSet && node);
   return NS_OK;
 }
 
 nsresult
 nsHTMLCSSUtils::SetCSSEnabled(bool aIsCSSPrefChecked)
@@ -1321,30 +1321,37 @@ nsHTMLCSSUtils::GetInlineStyles(nsIDOMEl
   return NS_OK;
 }
 
 already_AddRefed<nsIDOMElement>
 nsHTMLCSSUtils::GetElementContainerOrSelf(nsIDOMNode* aNode)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
   NS_ENSURE_TRUE(node, nsnull);
+  nsCOMPtr<nsIDOMElement> element =
+    do_QueryInterface(GetElementContainerOrSelf(node));
+  return element.forget();
+}
 
-  if (nsIDOMNode::DOCUMENT_NODE == node->NodeType()) {
+dom::Element*
+nsHTMLCSSUtils::GetElementContainerOrSelf(nsINode* aNode)
+{
+  MOZ_ASSERT(aNode);
+  if (nsIDOMNode::DOCUMENT_NODE == aNode->NodeType()) {
     return nsnull;
   }
 
+  nsINode* node = aNode;
   // Loop until we find an element.
   while (node && !node->IsElement()) {
     node = node->GetNodeParent();
   }
 
   NS_ENSURE_TRUE(node, nsnull);
-
-  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node);
-  return element.forget();
+  return node->AsElement();
 }
 
 nsresult
 nsHTMLCSSUtils::SetCSSProperty(nsIDOMElement * aElement,
                                const nsAString & aProperty,
                                const nsAString & aValue)
 {
   nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
--- a/editor/libeditor/html/nsHTMLCSSUtils.h
+++ b/editor/libeditor/html/nsHTMLCSSUtils.h
@@ -103,17 +103,18 @@ public:
   /** answers true if the given combination element_name/attribute_name
     * has a CSS equivalence in this implementation
     *
     * @return               a boolean saying if the tag/attribute has a css equiv
     * @param aNode          [IN] a DOM node
     * @param aProperty      [IN] an atom containing a HTML tag name
     * @param aAttribute     [IN] a string containing the name of a HTML attribute carried by the element above
     */
-  bool        IsCSSEditableProperty(nsIDOMNode * aNode, nsIAtom * aProperty, const nsAString * aAttribute);
+  bool IsCSSEditableProperty(nsIContent* aNode, nsIAtom* aProperty, const nsAString* aAttribute);
+  bool IsCSSEditableProperty(nsIDOMNode* aNode, nsIAtom* aProperty, const nsAString* aAttribute);
 
   /** adds/remove a CSS declaration to the STYLE atrribute carried by a given element
     *
     * @param aElement       [IN] a DOM element
     * @param aProperty      [IN] an atom containing the CSS property to set
     * @param aValue         [IN] a string containing the value of the CSS property
     * @param aSuppressTransaction [IN] a boolean indicating, when true,
     *                                  that no transaction should be recorded
@@ -188,17 +189,17 @@ public:
     *
     * @param aNode          [IN] a DOM node
     * @param aHTMLProperty  [IN] an atom containing an HTML property
     * @param aAttribute     [IN] a pointer to an attribute name or nsnull if irrelevant
     * @param aValueString   [OUT] the list of css values
     * @param aStyleType     [IN] SPECIFIED_STYLE_TYPE to query the specified style values
                                  COMPUTED_STYLE_TYPE  to query the computed style values
     */
-  nsresult    GetCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode * aNode,
+  nsresult    GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
                                                    nsIAtom * aHTMLProperty,
                                                    const nsAString * aAttribute,
                                                    nsAString & aValueString,
                                                    PRUint8 aStyleType);
 
   /** Does the node aNode (or his parent if it is not an element node) carries
     * the CSS equivalent styles to the HTML style for this node ?
     *
@@ -294,25 +295,27 @@ public:
                            PRUint32 * aLength);
 
   /** returns aNode itself if it is an element node, or the first ancestors being an element
     * node if aNode is not one itself
     *
     * @param aNode           [IN] a node
     * @param aElement        [OUT] the deepest element node containing aNode (possibly aNode itself)
     */
+  mozilla::dom::Element* GetElementContainerOrSelf(nsINode* aNode);
   already_AddRefed<nsIDOMElement> GetElementContainerOrSelf(nsIDOMNode* aNode);
 
   /**
    * Gets the default Window for a given node.
    *
    * @param aNode    the node we want the default Window for
    * @param aWindow  [OUT] the default Window
    */
-  nsresult        GetDefaultViewCSS(nsIDOMNode* aNode, nsIDOMWindow** aWindow);
+  nsresult GetDefaultViewCSS(nsINode* aNode, nsIDOMWindow** aWindow);
+  nsresult GetDefaultViewCSS(nsIDOMNode* aNode, nsIDOMWindow** aWindow);
 
 
 private:
 
   /** retrieves the css property atom from an enum
     *
     * @param aProperty          [IN] the enum value for the property
     * @param aAtom              [OUT] the corresponding atom
@@ -345,22 +348,22 @@ private:
     * @param aAttribute         [IN] a pointer to an attribute name or nsnull if irrelevant
     * @param aValue             [IN] the attribute value
     * @param aPropertyArray     [OUT] the array of css properties
     * @param aValueArray        [OUT] the array of values for the css properties above
     * @param aGetOrRemoveRequest [IN] a boolean value being true if the call to the current method
     *                                 is made for GetCSSEquivalentToHTMLInlineStyleSet or
     *                                 RemoveCSSEquivalentToHTMLInlineStyleSet
     */
-  void      GenerateCSSDeclarationsFromHTMLStyle(nsIDOMNode * aNode,
-                                                 nsIAtom * aHTMLProperty,
-                                                 const nsAString *aAttribute,
-                                                 const nsAString *aValue,
-                                                 nsTArray<nsIAtom*> & aPropertyArray,
-                                                 nsTArray<nsString> & aValueArray,
+  void      GenerateCSSDeclarationsFromHTMLStyle(mozilla::dom::Element* aNode,
+                                                 nsIAtom* aHTMLProperty,
+                                                 const nsAString* aAttribute,
+                                                 const nsAString* aValue,
+                                                 nsTArray<nsIAtom*>& aPropertyArray,
+                                                 nsTArray<nsString>& aValueArray,
                                                  bool aGetOrRemoveRequest);
 
   /** creates a Transaction for setting or removing a css property
     *
     * @param aElement           [IN] a DOM element
     * @param aProperty          [IN] a CSS property
     * @param aValue             [IN] the value to remove for this CSS property or the empty string if irrelevant
     * @param aTxn               [OUT] the created transaction
@@ -376,20 +379,22 @@ private:
    *
    * @param aNode               [IN] a DOM node
    * @param aProperty           [IN] a CSS property
    * @param aValue              [OUT] the retrieved value for this property
    * @param aWindow             [IN] the window we need in case we query computed styles
    * @param aStyleType          [IN] SPECIFIED_STYLE_TYPE to query the specified style values
    *                                 COMPUTED_STYLE_TYPE  to query the computed style values
    */
-  nsresult    GetCSSInlinePropertyBase(nsIDOMNode * aNode, nsIAtom * aProperty,
-                                       nsAString & aValue,
-                                       nsIDOMWindow* aWindow,
-                                       PRUint8 aStyleType);
+  nsresult GetCSSInlinePropertyBase(nsINode* aNode, nsIAtom* aProperty,
+                                    nsAString& aValue, nsIDOMWindow* aWindow,
+                                    PRUint8 aStyleType);
+  nsresult GetCSSInlinePropertyBase(nsIDOMNode* aNode, nsIAtom* aProperty,
+                                    nsAString& aValue, nsIDOMWindow* aWindow,
+                                    PRUint8 aStyleType);
 
 
 private:
   nsHTMLEditor            *mHTMLEditor;
   bool                    mIsCSSPrefChecked; 
 };
 
 #define NS_EDITOR_INDENT_INCREMENT_IN        0.4134f
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -856,26 +856,24 @@ nsHTMLEditRules::GetAlignment(bool *aMix
     blockParent = mHTMLEditor->GetBlockNodeParent(nodeToExamine);
 
   NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
 
   if (mHTMLEditor->IsCSSEnabled())
   {
     nsCOMPtr<nsIContent> blockParentContent = do_QueryInterface(blockParent);
     if (blockParentContent && 
-        mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(blockParent, dummyProperty, &typeAttrName))
+        mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(blockParentContent, dummyProperty, &typeAttrName))
     {
       // we are in CSS mode and we know how to align this element with CSS
       nsAutoString value;
       // let's get the value(s) of text-align or margin-left/margin-right
-      mHTMLEditor->mHTMLCSSUtils->GetCSSEquivalentToHTMLInlineStyleSet(blockParent,
-                                                     dummyProperty,
-                                                     &typeAttrName,
-                                                     value,
-                                                     COMPUTED_STYLE_TYPE);
+      mHTMLEditor->mHTMLCSSUtils->GetCSSEquivalentToHTMLInlineStyleSet(
+        blockParentContent, dummyProperty, &typeAttrName, value,
+        COMPUTED_STYLE_TYPE);
       if (value.EqualsLiteral("center") ||
           value.EqualsLiteral("-moz-center") ||
           value.EqualsLiteral("auto auto"))
       {
         *aAlign = nsIHTMLEditor::eCenter;
         return NS_OK;
       }
       if (value.EqualsLiteral("right") ||
@@ -6484,31 +6482,40 @@ nsHTMLEditRules::MakeTransitionList(nsCO
  ********************************************************/
  
 ///////////////////////////////////////////////////////////////////////////
 // IsInListItem: if aNode is the descendant of a listitem, return that li.
 //               But table element boundaries are stoppers on the search.
 //               Also stops on the active editor host (contenteditable).
 //               Also test if aNode is an li itself.
 //                       
-nsCOMPtr<nsIDOMNode> 
-nsHTMLEditRules::IsInListItem(nsIDOMNode *aNode)
-{
-  NS_ENSURE_TRUE(aNode, nsnull);  
-  if (nsHTMLEditUtils::IsListItem(aNode)) return aNode;
-  
-  nsCOMPtr<nsIDOMNode> parent, tmp;
-  aNode->GetParentNode(getter_AddRefs(parent));
-  
-  while (parent)
-  {
-    if (!mHTMLEditor->IsNodeInActiveEditor(parent)) return nsnull;
-    if (nsHTMLEditUtils::IsTableElement(parent)) return nsnull;
-    if (nsHTMLEditUtils::IsListItem(parent)) return parent;
-    tmp=parent; tmp->GetParentNode(getter_AddRefs(parent));
+already_AddRefed<nsIDOMNode>
+nsHTMLEditRules::IsInListItem(nsIDOMNode* aNode)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
+  nsCOMPtr<nsIDOMNode> retval = do_QueryInterface(IsInListItem(node));
+  return retval.forget();
+}
+
+nsINode*
+nsHTMLEditRules::IsInListItem(nsINode* aNode)
+{
+  NS_ENSURE_TRUE(aNode, nsnull);
+  if (aNode->IsElement() && nsHTMLEditUtils::IsListItem(aNode->AsElement())) {
+    return aNode;
+  }
+
+  nsINode* parent = aNode->GetNodeParent();
+  while (parent && mHTMLEditor->IsNodeInActiveEditor(parent) &&
+         !(parent->IsElement() &&
+           nsHTMLEditUtils::IsTableElement(parent->AsElement()))) {
+    if (nsHTMLEditUtils::IsListItem(parent->AsElement())) {
+      return parent;
+    }
+    parent = parent->GetNodeParent();
   }
   return nsnull;
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
 // ReturnInHeader: do the right thing for returns pressed in headers
 //                       
@@ -8874,101 +8881,79 @@ nsHTMLEditRules::AlignBlock(nsIDOMElemen
   return NS_OK;
 }
 
 nsresult
 nsHTMLEditRules::RelativeChangeIndentationOfElementNode(nsIDOMNode *aNode, PRInt8 aRelativeChange)
 {
   NS_ENSURE_ARG_POINTER(aNode);
 
-  if ( !( (aRelativeChange==1) || (aRelativeChange==-1) ) )
+  if (aRelativeChange != 1 && aRelativeChange != -1) {
     return NS_ERROR_ILLEGAL_VALUE;
+  }
 
   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
-  NS_ASSERTION(element, "not an element node");
-
-  if (element) {
-    nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, element);    
-    nsAutoString value;
-    nsresult res;
-    mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(aNode, marginProperty, value);
-    float f;
-    nsIAtom * unit;
-    mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, &unit);
-    if (0 == f) {
-      NS_IF_RELEASE(unit);
-      nsAutoString defaultLengthUnit;
-      mHTMLEditor->mHTMLCSSUtils->GetDefaultLengthUnit(defaultLengthUnit);
-      unit = NS_NewAtom(defaultLengthUnit);
-    }
-    nsAutoString unitString;
-    unit->ToString(unitString);
-    if      (nsEditProperty::cssInUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_IN * aRelativeChange;
-    else if (nsEditProperty::cssCmUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_CM * aRelativeChange;
-    else if (nsEditProperty::cssMmUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_MM * aRelativeChange;
-    else if (nsEditProperty::cssPtUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_PT * aRelativeChange;
-    else if (nsEditProperty::cssPcUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_PC * aRelativeChange;
-    else if (nsEditProperty::cssEmUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_EM * aRelativeChange;
-    else if (nsEditProperty::cssExUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_EX * aRelativeChange;
-    else if (nsEditProperty::cssPxUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_PX * aRelativeChange;
-    else if (nsEditProperty::cssPercentUnit == unit)
-              f += NS_EDITOR_INDENT_INCREMENT_PERCENT * aRelativeChange;    
-
-    NS_IF_RELEASE(unit);
-
-    if (0 < f) {
-      nsAutoString newValue;
-      newValue.AppendFloat(f);
-      newValue.Append(unitString);
-      mHTMLEditor->mHTMLCSSUtils->SetCSSProperty(element, marginProperty, newValue, false);
-    }
-    else {
-      mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(element, marginProperty, value, false);
-      // remove unnecessary DIV blocks:
-      // we could skip this section but that would cause a FAIL in
-      // editor/libeditor/html/tests/browserscope/richtext.html, which expects
-      // to unapply a CSS "indent" (<div style="margin-left: 40px;">) by
-      // removing the DIV container instead of just removing the CSS property.
-      nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-      if (nsHTMLEditUtils::IsDiv(aNode)
-          && (node != mHTMLEditor->GetActiveEditingHost())
-          && mHTMLEditor->IsNodeInActiveEditor(aNode)) {
-        // we deal with an editable DIV;
-        // let's see if it is useless and if we can remove it
-        nsCOMPtr<nsIDOMNamedNodeMap> attributeList;
-        res = element->GetAttributes(getter_AddRefs(attributeList));
-        NS_ENSURE_SUCCESS(res, res);
-        PRUint32 count;
-        attributeList->GetLength(&count);
-        if (!count) {
-          // the DIV has no attribute at all, let's remove it
-          res = mHTMLEditor->RemoveContainer(element);
-          NS_ENSURE_SUCCESS(res, res);
-        }
-        else if (1 == count) {
-          nsCOMPtr<nsIDOMNode> styleAttributeNode;
-          res = attributeList->GetNamedItem(NS_LITERAL_STRING("style"), 
-                                            getter_AddRefs(styleAttributeNode));
-          if (!styleAttributeNode) {
-            res = mHTMLEditor->RemoveContainer(element);
-            NS_ENSURE_SUCCESS(res, res);
-          }
-        }
-      }
-    }
-  }
-  return NS_OK;
+  if (!element) {
+    return NS_OK;
+  }
+
+  nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, element);    
+  nsAutoString value;
+  mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(aNode, marginProperty, value);
+  float f;
+  nsCOMPtr<nsIAtom> unit;
+  mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
+  if (0 == f) {
+    nsAutoString defaultLengthUnit;
+    mHTMLEditor->mHTMLCSSUtils->GetDefaultLengthUnit(defaultLengthUnit);
+    unit = do_GetAtom(defaultLengthUnit);
+  }
+  if      (nsEditProperty::cssInUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_IN * aRelativeChange;
+  else if (nsEditProperty::cssCmUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_CM * aRelativeChange;
+  else if (nsEditProperty::cssMmUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_MM * aRelativeChange;
+  else if (nsEditProperty::cssPtUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_PT * aRelativeChange;
+  else if (nsEditProperty::cssPcUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_PC * aRelativeChange;
+  else if (nsEditProperty::cssEmUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_EM * aRelativeChange;
+  else if (nsEditProperty::cssExUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_EX * aRelativeChange;
+  else if (nsEditProperty::cssPxUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_PX * aRelativeChange;
+  else if (nsEditProperty::cssPercentUnit == unit)
+            f += NS_EDITOR_INDENT_INCREMENT_PERCENT * aRelativeChange;    
+
+  if (0 < f) {
+    nsAutoString newValue;
+    newValue.AppendFloat(f);
+    newValue.Append(nsDependentAtomString(unit));
+    mHTMLEditor->mHTMLCSSUtils->SetCSSProperty(element, marginProperty, newValue, false);
+    return NS_OK;
+  }
+
+  mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(element, marginProperty, value, false);
+
+  // remove unnecessary DIV blocks:
+  // we could skip this section but that would cause a FAIL in
+  // editor/libeditor/html/tests/browserscope/richtext.html, which expects
+  // to unapply a CSS "indent" (<div style="margin-left: 40px;">) by
+  // removing the DIV container instead of just removing the CSS property.
+  nsCOMPtr<dom::Element> node = do_QueryInterface(aNode);
+  if (!node || !node->IsHTML(nsGkAtoms::div) ||
+      node == mHTMLEditor->GetActiveEditingHost() ||
+      !mHTMLEditor->IsNodeInActiveEditor(node) ||
+      nsHTMLEditor::HasAttributes(node)) {
+    return NS_OK;
+  }
+
+  return mHTMLEditor->RemoveContainer(element);
 }
 
 //
 // Support for Absolute Positioning
 //
 
 nsresult
 nsHTMLEditRules::WillAbsolutePosition(nsISelection *aSelection, bool *aCancel, bool * aHandled)
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -181,17 +181,18 @@ protected:
   nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
   nsresult DidAbsolutePosition();
   nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsAString *alignType);
   nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType);
   nsresult AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
                                   nsIDOMNode *aNode);
   nsresult GetFormatString(nsIDOMNode *aNode, nsAString &outFormat);
   nsresult GetInnerContent(nsIDOMNode *aNode, nsCOMArray<nsIDOMNode>& outArrayOfNodes, PRInt32 *aIndex, bool aList = true, bool aTble = true);
-  nsCOMPtr<nsIDOMNode> IsInListItem(nsIDOMNode *aNode);
+  already_AddRefed<nsIDOMNode> IsInListItem(nsIDOMNode* aNode);
+  nsINode* IsInListItem(nsINode* aNode);
   nsresult ReturnInHeader(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
   nsresult ReturnInParagraph(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, bool *aCancel, bool *aHandled);
   nsresult SplitParagraph(nsIDOMNode *aPara,
                           nsIDOMNode *aBRNode, 
                           nsISelection *aSelection,
                           nsCOMPtr<nsIDOMNode> *aSelNode, 
                           PRInt32 *aOffset);
   nsresult ReturnInListItem(nsISelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -3990,39 +3990,36 @@ void nsHTMLEditor::IsTextPropertySetByCo
 // Note: Table Editing methods are implemented in nsTableEditor.cpp
 //
 
 
 bool
 nsHTMLEditor::IsNodeInActiveEditor(nsIDOMNode* aNode)
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  if (!node) {
-    return false;
-  }
+  return node && IsNodeInActiveEditor(node);
+}
+
+bool
+nsHTMLEditor::IsNodeInActiveEditor(nsINode* aNode)
+{
   nsIContent* activeEditingHost = GetActiveEditingHost();
   if (!activeEditingHost) {
     return false;
   }
-  return nsContentUtils::ContentIsDescendantOf(node, activeEditingHost);
+  return nsContentUtils::ContentIsDescendantOf(aNode, activeEditingHost);
 }
 
 bool
 nsHTMLEditor::SetCaretInTableCell(nsIDOMElement* aElement)
 {
-  if (!aElement || !IsNodeInActiveEditor(aElement)) {
-    return false;
-  }
-
   nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
-  if (!element || !element->IsHTML()) {
-    return false;
-  }
-
-  if (!nsHTMLEditUtils::IsTableElement(element)) {
+  if (!element || !element->IsHTML() ||
+      !nsHTMLEditUtils::IsTableElement(element) ||
+      !IsNodeInActiveEditor(element)) {
     return false;
   }
 
   nsIContent* node = element;
   while (node->HasChildren()) {
     node = node->GetFirstChild();
   }
 
@@ -4069,17 +4066,17 @@ nsCOMPtr<nsIDOMElement> nsHTMLEditor::Fi
   NS_ENSURE_TRUE(rootContent, 0);
 
   nsCOMPtr<nsIDOMNode> rootNode (do_QueryInterface(rootContent));
   NS_ENSURE_TRUE(rootNode, 0);
 
   nsString prestr ("PRE");  // GetFirstNodeOfType requires capitals
   nsCOMPtr<nsIDOMNode> preNode;
   if (NS_FAILED(nsEditor::GetFirstNodeOfType(rootNode, prestr,
-                                                 getter_AddRefs(preNode))))
+                                             getter_AddRefs(preNode))))
     return 0;
 
   return do_QueryInterface(preNode);
 }
 #endif /* PRE_NODE_IN_BODY */
 
 /* this method scans the selection for adjacent text nodes
  * and collapses them into a single text node.
@@ -4103,20 +4100,21 @@ nsHTMLEditor::CollapseAdjacentTextNodes(
   nsCOMPtr<nsIContentIterator> iter =
     do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &result);
   NS_ENSURE_SUCCESS(result, result);
 
   iter->Init(aInRange);
 
   while (!iter->IsDone())
   {
-    nsCOMPtr<nsIDOMCharacterData> text = do_QueryInterface(iter->GetCurrentNode());
-    if (text && IsEditable(text))
-    {
-      textNodes.AppendElement(text);
+    nsINode* node = iter->GetCurrentNode();
+    if (node->NodeType() == nsIDOMNode::TEXT_NODE &&
+        IsEditable(static_cast<nsIContent*>(node))) {
+      nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(node);
+      textNodes.AppendElement(domNode);
     }
 
     iter->Next();
   }
 
   // now that I have a list of text nodes, collapse adjacent text nodes
   // NOTE: assumption that JoinNodes keeps the righthand node
   while (textNodes.Length() > 1)
@@ -4145,20 +4143,20 @@ nsHTMLEditor::CollapseAdjacentTextNodes(
   }
 
   return result;
 }
 
 NS_IMETHODIMP 
 nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
 {
-  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
+  dom::Element* rootElement = GetRoot();
   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
 
-  return aSelection->Collapse(rootElement,0);
+  return aSelection->CollapseNative(rootElement, 0);
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
 // RemoveBlockContainer: remove inNode, reparenting it's children into their
 //                  the parent of inNode.  In addition, INSERT ANY BR's NEEDED
 //                  TO PRESERVE IDENTITY OF REMOVED BLOCK.
 //
@@ -4915,36 +4913,34 @@ nsHTMLEditor::RemoveAttributeOrEquivalen
       res = RemoveAttribute(aElement, aAttribute);
   }
   return res;
 }
 
 nsresult
 nsHTMLEditor::SetIsCSSEnabled(bool aIsCSSPrefChecked)
 {
-  nsresult  err = NS_ERROR_NOT_INITIALIZED;
-  if (mHTMLCSSUtils)
-  {
-    err = mHTMLCSSUtils->SetCSSEnabled(aIsCSSPrefChecked);
+  if (!mHTMLCSSUtils) {
+    return NS_ERROR_NOT_INITIALIZED;
   }
+
+  nsresult rv = mHTMLCSSUtils->SetCSSEnabled(aIsCSSPrefChecked);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // Disable the eEditorNoCSSMask flag if we're enabling StyleWithCSS.
-  if (NS_SUCCEEDED(err)) {
-    PRUint32 flags = mFlags;
-    if (aIsCSSPrefChecked) {
-      // Turn off NoCSS as we're enabling CSS
-      flags &= ~eEditorNoCSSMask;
-    } else {
-      // Turn on NoCSS, as we're disabling CSS.
-      flags |= eEditorNoCSSMask;
-    }
-
-    err = SetFlags(flags);
-    NS_ENSURE_SUCCESS(err, err);
+  PRUint32 flags = mFlags;
+  if (aIsCSSPrefChecked) {
+    // Turn off NoCSS as we're enabling CSS
+    flags &= ~eEditorNoCSSMask;
+  } else {
+    // Turn on NoCSS, as we're disabling CSS.
+    flags |= eEditorNoCSSMask;
   }
-  return err;
+
+  return SetFlags(flags);
 }
 
 // Set the block background color
 NS_IMETHODIMP
 nsHTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
 {
   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
   ForceCompositionEnd();
@@ -5260,18 +5256,17 @@ nsHTMLEditor::CopyLastEditableChildStyle
     NS_ENSURE_SUCCESS(res, res);
     child = tmp;
   }
   if (deepestStyle) {
     nsCOMPtr<nsIDOMNode> outBRNode;
     res = CreateBR(deepestStyle, 0, address_of(outBRNode));
     NS_ENSURE_SUCCESS(res, res);
     // Getters must addref
-    *aOutBrNode = outBRNode;
-    NS_ADDREF(*aOutBrNode);
+    outBRNode.forget(aOutBrNode);
   }
   return NS_OK;
 }
 
 nsresult
 nsHTMLEditor::GetElementOrigin(nsIDOMElement * aElement, PRInt32 & aX, PRInt32 & aY)
 {
   aX = 0;
@@ -5405,19 +5400,17 @@ nsHTMLEditor::GetSelectionContainer(nsID
       nsCOMPtr<nsIDOMNode> parent;
       res = focusNode->GetParentNode(getter_AddRefs(parent));
       NS_ENSURE_SUCCESS(res, res);
       focusNode = parent;
     }
   }
 
   nsCOMPtr<nsIDOMElement> focusElement = do_QueryInterface(focusNode);
-  *aReturn = focusElement;
-  NS_IF_ADDREF(*aReturn);
-
+  focusElement.forget(aReturn);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::IsAnonymousElement(nsIDOMElement * aElement, bool * aReturn)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
@@ -5634,18 +5627,17 @@ nsHTMLEditor::GetFocusedNode()
   nsCOMPtr<nsIDOMElement> focusedElement;
   fm->GetFocusedElement(getter_AddRefs(focusedElement));
   if (focusedElement) {
     nsCOMPtr<nsINode> node = do_QueryInterface(focusedElement);
     return node.forget();
   }
 
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
-  nsCOMPtr<nsINode> node = do_QueryInterface(doc);
-  return node.forget();
+  return doc.forget();
 }
 
 bool
 nsHTMLEditor::OurWindowHasFocus()
 {
   NS_ENSURE_TRUE(mDocWeak, false);
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, false);
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -66,16 +66,19 @@
 #include "nsIHTMLInlineTableEditor.h"
 #include "nsIHTMLObjectResizeListener.h"
 
 #include "nsIDocumentObserver.h"
 
 #include "nsPoint.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
+#include "nsAttrName.h"
+
+#include "mozilla/dom/Element.h"
 
 class nsIDOMKeyEvent;
 class nsITransferable;
 class nsIDocumentEncoder;
 class nsIClipboard;
 class TypeInState;
 class nsIContentFilter;
 class nsIURL;
@@ -420,16 +423,23 @@ public:
   nsresult RemoveStyleSheetFromList(const nsAString &aURL);
 
   bool IsCSSEnabled()
   {
     // TODO: removal of mCSSAware and use only the presence of mHTMLCSSUtils
     return mCSSAware && mHTMLCSSUtils && mHTMLCSSUtils->IsCSSPrefChecked();
   }
 
+  static bool HasAttributes(mozilla::dom::Element* aElement)
+  {
+    MOZ_ASSERT(aElement);
+    PRUint32 attrCount = aElement->GetAttrCount();
+    return attrCount > 1 ||
+           (1 == attrCount && !aElement->GetAttrNameAt(0)->Equals(nsGkAtoms::mozdirty));
+  }
 
 protected:
 
   NS_IMETHOD  InitRules();
 
   // Create the event listeners for the editor to install
   virtual void CreateEventListeners();
 
@@ -442,16 +452,17 @@ protected:
   // Get the focused node of this editor.
   // @return    If the editor has focus, this returns the focused node.
   //            Otherwise, returns null.
   already_AddRefed<nsINode> GetFocusedNode();
 
   // Return TRUE if aElement is a table-related elemet and caret was set
   bool SetCaretInTableCell(nsIDOMElement* aElement);
   bool IsNodeInActiveEditor(nsIDOMNode* aNode);
+  bool IsNodeInActiveEditor(nsINode* aNode);
 
   // key event helpers
   NS_IMETHOD TabInTable(bool inIsShift, bool *outHandled);
   NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset, 
                       nsCOMPtr<nsIDOMNode> *outBRNode, nsIEditor::EDirection aSelect = nsIEditor::eNone);
 
 // Table Editing (implemented in nsTableEditor.cpp)
 
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -1,19 +1,13 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Chris Jones <jones.chris.g@gmail.com>
- *   Jim Straus <jstraus@mozilla.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Hal.h"
 #include "HalImpl.h"
 #include "HalSandbox.h"
 #include "mozilla/Util.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Observer.h"
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -1,22 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Chris Jones <jones.chris.g@gmail.com>
- *   Jim Straus <jstraus@mozilla.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_Hal_h
-#define mozilla_Hal_h 1
+#define mozilla_Hal_h
 
 #include "mozilla/hal_sandbox/PHal.h"
 #include "base/basictypes.h"
 #include "mozilla/Types.h"
 #include "nsTArray.h"
 #include "prlog.h"
 #include "mozilla/dom/battery/Types.h"
 #include "mozilla/dom/network/Types.h"
--- a/hal/HalImpl.h
+++ b/hal/HalImpl.h
@@ -1,18 +1,13 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Chris Jones <jones.chris.g@gmail.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_HalImpl_h
 #define mozilla_HalImpl_h
 
 #define MOZ_HAL_NAMESPACE hal_impl
 #undef mozilla_Hal_h
 #undef mozilla_HalInternal_h
 #include "Hal.h"
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -1,18 +1,12 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
- *   Jim Straus <jstraus@mozilla.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_hal_Types_h
 #define mozilla_hal_Types_h
 
 #include "IPCMessageUtils.h"
 
 namespace mozilla {
 namespace hal {
--- a/hal/fallback/FallbackHal.cpp
+++ b/hal/fallback/FallbackHal.cpp
@@ -1,19 +1,13 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Chris Jones <jones.chris.g@gmail.com>
- *   Jim Straus <jstraus@mozilla.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Hal.h"
 #include "mozilla/dom/battery/Constants.h"
 #include "mozilla/dom/network/Constants.h"
 
 using mozilla::hal::WindowIdentifier;
 
 namespace mozilla {
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -1,21 +1,13 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Chris Jones <jones.chris.g@gmail.com>
- *   Michael Wu <mwu@mozilla.com>
- *   Justin Lebar <justin.lebar@gmail.com>
- *   Jim Straus <jstraus@mozilla.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "hardware_legacy/uevent.h"
 #include "Hal.h"
 #include "HalImpl.h"
 #include "mozilla/dom/battery/Constants.h"
 #include "mozilla/FileUtils.h"
 #include "nsAlgorithm.h"
 #include "nsThreadUtils.h"
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -1,19 +1,13 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Chris Jones <jones.chris.g@gmail.com>
- *   Jim Straus <jstraus@mozilla.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Hal.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/battery/Types.h"
--- a/hal/sandbox/SandboxHal.h
+++ b/hal/sandbox/SandboxHal.h
@@ -1,18 +1,13 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
-/* ***** BEGIN LICENSE BLOCK *****
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
- * Contributor(s):
- *   Chris Jones <jones.chris.g@gmail.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_SandboxHal_h
 #define mozilla_SandboxHal_h
 
 namespace mozilla {
 namespace hal_sandbox {
 
 class PHalChild;
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -511,17 +511,17 @@ GetMethodInfo(JSContext *cx, jsval *vp, 
     NS_ASSERTION(JS_ObjectIsFunction(cx, funobj),
                  "JSNative callee should be Function object");
     JSString *str = JS_GetFunctionId(JS_GetObjectFunction(funobj));
     jsid methodId = str ? INTERNED_STRING_TO_JSID(cx, str) : JSID_VOID;
     GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceNamep);
     *memberIdp = methodId;
 }
 
-static JSBool
+static bool
 ThrowCallFailed(JSContext *cx, nsresult rv,
                 const char *ifaceName, jsid memberId, const char *memberName)
 {
     /* Only one of memberId or memberName should be given. */
     JS_ASSERT(JSID_IS_VOID(memberId) != !memberName);
 
     // From XPCThrower::ThrowBadResult.
     char* sz;
@@ -587,22 +587,22 @@ xpc_qsThrowMethodFailed(JSContext *cx, n
 
 JSBool
 xpc_qsThrowMethodFailedWithCcx(XPCCallContext &ccx, nsresult rv)
 {
     ThrowBadResult(rv, ccx);
     return false;
 }
 
-void
+bool
 xpc_qsThrowMethodFailedWithDetails(JSContext *cx, nsresult rv,
                                    const char *ifaceName,
                                    const char *memberName)
 {
-    ThrowCallFailed(cx, rv, ifaceName, JSID_VOID, memberName);
+    return ThrowCallFailed(cx, rv, ifaceName, JSID_VOID, memberName);
 }
 
 static void
 ThrowBadArg(JSContext *cx, nsresult rv, const char *ifaceName,
             jsid memberId, const char *memberName, uintN paramnum)
 {
     /* Only one memberId or memberName should be given. */
     JS_ASSERT(JSID_IS_VOID(memberId) != !memberName);
--- a/js/xpconnect/src/XPCQuickStubs.h
+++ b/js/xpconnect/src/XPCQuickStubs.h
@@ -192,17 +192,17 @@ xpc_qsThrowGetterSetterFailed(JSContext 
  * See NOTE at xpc_qsThrowGetterSetterFailed.
  */
 JSBool
 xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp);
 
 JSBool
 xpc_qsThrowMethodFailedWithCcx(XPCCallContext &ccx, nsresult rv);
 
-void
+bool
 xpc_qsThrowMethodFailedWithDetails(JSContext *cx, nsresult rv,
                                    const char *ifaceName,
                                    const char *memberName);
 
 /**
  * Fail after converting a method argument fails.
  *
  * See NOTE at xpc_qsThrowGetterSetterFailed.
--- a/js/xpconnect/src/dombindingsgen.py
+++ b/js/xpconnect/src/dombindingsgen.py
@@ -575,20 +575,18 @@ def writeBindingStub(f, classname, membe
             f.write("    JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));\n"
                     "    if (!%sWrapper::instanceIsListObject(cx, obj, callee))\n"
                     "        return false;\n" % classname)
         else:
             f.write("    if (!%sWrapper::instanceIsListObject(cx, obj, NULL))\n"
                     "        return false;\n" % classname)
         return "%sWrapper::getListObject(obj)" % classname
     def writeCheckForFailure(f, isMethod, isGeter, haveCcx):
-        f.write("    if (NS_FAILED(rv)) {\n"
-                "        xpc_qsThrowMethodFailedWithDetails(cx, rv, \"%s\", \"%s\");\n"
-                "        return JS_FALSE;\n"
-                "    }\n" % (classname, member.name))
+        f.write("    if (NS_FAILED(rv))\n"
+                "        return xpc_qsThrowMethodFailedWithDetails(cx, rv, \"%s\", \"%s\");\n" % (classname, member.name))
     def writeResultWrapping(f, member, jsvalPtr, jsvalRef):
         if member.kind == 'method' and member.notxpcom and len(member.params) > 0 and member.params[len(member.params) - 1].paramtype == 'out':
             assert member.params[len(member.params) - 1].realtype.kind == 'native' and member.params[len(member.params) - 1].realtype.nativename == 'nsWrapperCache'
             template = "    return Wrap(cx, obj, result, cache, ${jsvalPtr});\n"
         else:
             template = "    return Wrap(cx, obj, result, ${jsvalPtr});\n"
         writeResultConv(f, member.realtype, template, jsvalPtr, jsvalRef)
 
--- a/toolkit/devtools/debugger/dbg-client.jsm
+++ b/toolkit/devtools/debugger/dbg-client.jsm
@@ -190,25 +190,36 @@ function eventSource(aProto) {
  */
 const ThreadStateTypes = {
   "paused": "paused",
   "resumed": "attached",
   "detached": "detached"
 };
 
 /**
+ * Set of protocol messages that are sent by the server without a prior request
+ * by the client.
+ */
+const UnsolicitedNotifications = {
+  "newScript": "newScript",
+  "tabDetached": "tabDetached",
+  "tabNavigated": "tabNavigated"
+};
+
+/**
  * Set of debug protocol request types that specify the protocol request being
  * sent to the server.
  */
 const DebugProtocolTypes = {
   "attach": "attach",
   "clientEvaluate": "clientEvaluate",
   "delete": "delete",
   "detach": "detach",
   "frames": "frames",
+  "interrupt": "interrupt",
   "listTabs": "listTabs",
   "nameAndParameters": "nameAndParameters",
   "ownPropertyNames": "ownPropertyNames",
   "property": "property",
   "prototype": "prototype",
   "prototypeAndProperties": "prototypeAndProperties",
   "resume": "resume",
   "scripts": "scripts",
@@ -403,22 +414,25 @@ DebuggerClient.prototype = {
       this.notify("connected",
                   aPacket.applicationType,
                   aPacket.traits);
       return;
     }
 
     try {
       if (!aPacket.from) {
-        dumpn("Server did not specify an actor, dropping packet: " + JSON.stringify(aPacket));
+        Cu.reportError("Server did not specify an actor, dropping packet: " +
+                       JSON.stringify(aPacket));
         return;
       }
 
       let onResponse;
-      if (aPacket.from in this._activeRequests) {
+      // Don't count unsolicited notifications as responses.
+      if (aPacket.from in this._activeRequests &&
+          !(aPacket.type in UnsolicitedNotifications)) {
         onResponse = this._activeRequests[aPacket.from].onResponse;
         delete this._activeRequests[aPacket.from];
       }
 
       // paused/resumed/detached get special treatment...
       if (aPacket.type in ThreadStateTypes &&
           aPacket.from in this._threadClients) {
         this._threadClients[aPacket.from]._onThreadState(aPacket);
@@ -504,22 +518,23 @@ function ThreadClient(aClient, aActor) {
   this._actor = aActor;
   this._frameCache = [];
   this._scriptCache = {};
 }
 
 ThreadClient.prototype = {
   _state: "paused",
   get state() { return this._state; },
+  get paused() { return this._state === "paused"; },
 
   _actor: null,
   get actor() { return this._actor; },
 
   _assertPaused: function TC_assertPaused(aCommand) {
-    if (this._state !== "paused") {
+    if (!this.paused) {
       throw aCommand + " command sent while not paused.";
     }
   },
 
   /**
    * Resume a paused thread.
    *
    * @param function aOnResponse
@@ -541,16 +556,31 @@ ThreadClient.prototype = {
       }
       if (aOnResponse) {
         aOnResponse(aResponse);
       }
     });
   },
 
   /**
+   * Interrupt a running thread.
+   *
+   * @param function aOnResponse
+   *        Called with the response packet.
+   */
+  interrupt: function TC_interrupt(aOnResponse) {
+    let packet = { to: this._actor, type: DebugProtocolTypes.interrupt };
+    this._client.request(packet, function(aResponse) {
+      if (aOnResponse) {
+        aOnResponse(aResponse);
+      }
+    });
+  },
+
+  /**
    * Send a clientEvaluate packet to the debuggee. Response
    * will be a resume packet.
    */
   eval: function TC_eval(aFrame, aExpression, aOnResponse) {
     this._assertPaused("eval");
 
     // Put the client in a tentative "resuming" state so we can prevent
     // further requests that should only be sent in the paused state.
@@ -590,34 +620,59 @@ ThreadClient.prototype = {
       }
     });
   },
 
   /**
    * Request to set a breakpoint in the specified location.
    *
    * @param aLocation object
-   *        The source location object where the breakpoint
-   *        will be set.
+   *        The source location object where the breakpoint will be set.
    * @param aOnResponse integer
    *        Called with the thread's response.
    */
   setBreakpoint: function TC_setBreakpoint(aLocation, aOnResponse) {
-    this._assertPaused("setBreakpoint");
+    // A helper function that sets the breakpoint.
+    let doSetBreakpoint = function _doSetBreakpoint(aCallback) {
+      let packet = { to: this._actor, type: DebugProtocolTypes.setBreakpoint,
+                     location: aLocation };
+      this._client.request(packet, function (aResponse) {
+          if (aOnResponse) {
+            if (aResponse.error) {
+              if (aCallback) {
+                aCallback(aOnResponse.bind(undefined, aResponse));
+              } else {
+                aOnResponse(aResponse);
+              }
+              return;
+            }
+            let bpClient = new BreakpointClient(this._client, aResponse.actor);
+            if (aCallback) {
+              aCallback(aOnResponse(aResponse, bpClient));
+            } else {
+              aOnResponse(aResponse, bpClient);
+            }
+          }
+        }.bind(this));
+    }.bind(this);
 
-    let self = this;
-    let packet = { to: this._actor, type: DebugProtocolTypes.setBreakpoint,
-                   location: aLocation };
-    this._client.request(packet, function (aResponse) {
-                         if (aOnResponse) {
-                           let bpClient = new BreakpointClient(self._client,
-                                                               aResponse.actor);
-                           aOnResponse(aResponse, bpClient);
-                         }
-                       });
+    // If the debuggee is paused, just set the breakpoint.
+    if (this.paused) {
+      doSetBreakpoint();
+      return;
+    }
+    // Otherwise, force a pause in order to set the breakpoint.
+    this.interrupt(function(aResponse) {
+      if (aResponse.error) {
+        // Can't set the breakpoint if pausing failed.
+        aOnResponse(aResponse);
+        return;
+      }
+      doSetBreakpoint(this.resume.bind(this));
+    }.bind(this));
   },
 
   /**
    * Request the loaded scripts for the current thread.
    *
    * @param aOnResponse integer
    *        Called with the thread's response.
    */
@@ -691,18 +746,17 @@ ThreadClient.prototype = {
    * and can fill it using the fillFrames method.
    */
   get cachedFrames() { return this._frameCache; },
 
   /**
    * true if there are more stack frames available on the server.
    */
   get moreFrames() {
-    return this.state === "paused"
-      && (!this._frameCache || this._frameCache.length == 0
+    return this.paused && (!this._frameCache || this._frameCache.length == 0
           || !this._frameCache[this._frameCache.length - 1].oldest);
   },
 
   /**
    * Ensure that at least aTotal stack frames have been loaded in the
    * ThreadClient's stack frame cache. A framesadded event will be
    * sent when the stack frame cache is updated.
    *
--- a/toolkit/devtools/debugger/server/dbg-browser-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-browser-actors.js
@@ -360,35 +360,35 @@ BrowserTabActor.prototype = {
     }
 
     this._detach();
 
     return { type: "detached" };
   },
 
   /**
-   * Suppresses content-initiated events. Called right before entering the
-   * nested event loop.
+   * Prepare to enter a nested event loop by disabling debuggee events.
    */
   preNest: function BTA_preNest() {
-    this.browser.contentWindow
-        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIDOMWindowUtils)
-        .suppressEventHandling(true);
+    let windowUtils = this.browser.contentWindow
+                          .QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIDOMWindowUtils);
+    windowUtils.suppressEventHandling(true);
+    windowUtils.suspendTimeouts();
   },
 
   /**
-   * Re-enables content-initiated events. Called right after exiting the
-   * nested event loop.
+   * Prepare to exit a nested event loop by enabling debuggee events.
    */
   postNest: function BTA_postNest(aNestData) {
-    this.browser.contentWindow
-        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIDOMWindowUtils)
-        .suppressEventHandling(false);
+    let windowUtils = this.browser.contentWindow
+                          .QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIDOMWindowUtils);
+    windowUtils.resumeTimeouts();
+    windowUtils.suppressEventHandling(false);
   },
 
   /**
    * Handle location changes, by sending a tabNavigated notification to the
    * client.
    */
   onWindowCreated: function BTA_onWindowCreated(evt) {
     if (evt.target === this.browser.contentDocument) {
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -44,18 +44,18 @@
  */
 /**
  * Creates a ThreadActor.
  *
  * ThreadActors manage a JSInspector object and manage execution/inspection
  * of debuggees.
  *
  * @param aHooks object
- *        An object with preNest and postNest methods that can be called when
- *        entering and exiting a nested event loop.
+ *        An object with preNest and postNest methods for calling when entering
+ *        and exiting a nested event loop.
  */
 function ThreadActor(aHooks)
 {
   this._state = "detached";
   this._frameActors = [];
   this._environmentActors = [];
   this._hooks = aHooks ? aHooks : {};
 }
@@ -171,17 +171,17 @@ ThreadActor.prototype = {
 
       // Start a nested event loop.
       this._nest();
 
       // We already sent a response to this request, don't send one
       // now.
       return null;
     } catch(e) {
-      dumpn(e);
+      Cu.reportError(e);
       return { error: "notAttached", message: e.toString() };
     }
   },
 
   onDetach: function TA_onDetach(aRequest) {
     this.disconnect();
     return { type: "detached" };
   },
@@ -281,20 +281,18 @@ ThreadActor.prototype = {
    */
   onSetBreakpoint: function TA_onSetBreakpoint(aRequest) {
     if (this.state !== "paused") {
       return { error: "wrongState",
                message: "Breakpoints can only be set while the debuggee is paused."};
     }
 
     let location = aRequest.location;
-    // TODO: deal with actualLocation being different from the provided location
     if (!this._scripts[location.url] || location.line < 0) {
-      return { from: this.actorID,
-               error: "noScript" };
+      return { error: "noScript" };
     }
     // Fetch the list of scripts in that url.
     let scripts = this._scripts[location.url];
     // Fetch the specified script in that list.
     let script = null;
     for (let i = location.line; i >= 0; i--) {
       // Stop when the first script that contains this location is found.
       if (scripts[i]) {
@@ -302,29 +300,79 @@ ThreadActor.prototype = {
         // good.
         if (i + scripts[i].lineCount < location.line) {
           break;
         }
         script = scripts[i];
         break;
       }
     }
+
     if (!script) {
-      return { from: this.actorID,
-               error: "noScript" };
+      return { error: "noScript" };
     }
+
+    script = this._getInnermostContainer(script, location.line);
     let bpActor = new BreakpointActor(script, this);
     this.breakpointActorPool.addActor(bpActor);
-    var offsets = script.getLineOffsets(location.line);
-    for (var i = 0; i < offsets.length; i++) {
+
+    let offsets = script.getLineOffsets(location.line);
+    let codeFound = false;
+    for (let i = 0; i < offsets.length; i++) {
       script.setBreakpoint(offsets[i], bpActor);
+      codeFound = true;
+    }
+
+    let actualLocation;
+    if (offsets.length == 0) {
+      // No code at that line in any script, skipping forward.
+      let lines = script.getAllOffsets();
+      for (let line = location.line; line < lines.length; ++line) {
+        if (lines[line]) {
+          for (let i = 0; i < lines[line].length; i++) {
+            script.setBreakpoint(lines[line][i], bpActor);
+            codeFound = true;
+          }
+          actualLocation = location;
+          actualLocation.line = line;
+          break;
+        }
+      }
+    }
+    if (!codeFound) {
+      bpActor.onDelete();
+      return  { error: "noCodeAtLineColumn" };
     }
-    let packet = { from: this.actorID,
-                   actor: bpActor.actorID };
-    return packet;
+
+    return { actor: bpActor.actorID, actualLocation: actualLocation };
+  },
+
+  /**
+   * Get the innermost script that contains this line, by looking through child
+   * scripts of the supplied script.
+   *
+   * @param aScript Debugger.Script
+   *        The source script.
+   * @param aLine number
+   *        The line number.
+   */
+  _getInnermostContainer: function TA__getInnermostContainer(aScript, aLine) {
+    let children = aScript.getChildScripts();
+    if (children.length > 0) {
+      for (let i = 0; i < children.length; i++) {
+        let child = children[i];
+        // Stop when the first script that contains this location is found.
+        if (child.startLine <= aLine &&
+            child.startLine + child.lineCount > aLine) {
+          return this._getInnermostContainer(child, aLine);
+        }
+      }
+    }
+    // Location not found in children, this is the innermost containing script.
+    return aScript;
   },
 
   /**
    * Handle a protocol request to return the list of loaded scripts.
    */
   onScripts: function TA_onScripts(aRequest) {
     let scripts = [];
     for (let url in this._scripts) {
@@ -342,16 +390,56 @@ ThreadActor.prototype = {
     }
 
     let packet = { from: this.actorID,
                    scripts: scripts };
     return packet;
   },
 
   /**
+   * Handle a protocol request to pause the debuggee.
+   */
+  onInterrupt: function TA_onScripts(aRequest) {
+    if (this.state == "exited") {
+      return { type: "exited" };
+    } else if (this.state == "paused") {
+      // TODO: return the actual reason for the existing pause.
+      return { type: "paused", why: { type: "alreadyPaused" } };
+    } else if (this.state != "running") {
+      return { error: "wrongState",
+               message: "Received interrupt request in " + this.state +
+                        " state." };
+    }
+
+    try {
+      // Put ourselves in the paused state.
+      let packet = this._paused();
+      if (!packet) {
+        return { error: "notInterrupted" };
+      }
+      packet.why = { type: "interrupted" };
+
+      // Send the response to the interrupt request now (rather than
+      // returning it), because we're going to start a nested event loop
+      // here.
+      this.conn.send(packet);
+
+      // Start a nested event loop.
+      this._nest();
+
+      // We already sent a response to this request, don't send one
+      // now.
+      return null;
+    } catch(e) {
+      Cu.reportError(e);
+      return { error: "notInterrupted", message: e.toString() };
+    }
+  },
+
+  /**
    * Return the Debug.Frame for a frame mentioned by the protocol.
    */
   _requestFrame: function TA_requestFrame(aFrameID) {
     // XXXspec: doesn't actually specify how frames are named.  By
     // depth?  By actor?  Both?
     if (!aFrameID) {
       return this._youngestFrame;
     }
@@ -621,17 +709,18 @@ ThreadActor.prototype = {
       let packet = this._paused(aFrame);
       if (!packet) {
         return undefined;
       }
       packet.why = { type: "debuggerStatement" };
       this.conn.send(packet);
       return this._nest();
     } catch(e) {
-      dumpn("Got an exception during onDebuggerStatement: " + e + ': ' + e.stack);
+      Cu.reportError("Got an exception during onDebuggerStatement: " + e +
+                     ": " + e.stack);
       return undefined;
     }
   },
 
   /**
    * A function that the engine calls when a new script has been loaded into a
    * debuggee compartment. If the new code is part of a function, aFunction is
    * a Debugger.Object reference to the function object. (Not all code is part
@@ -640,20 +729,16 @@ ThreadActor.prototype = {
    * onNewScript without an accompanying function argument.)
    *
    * @param aScript Debugger.Script
    *        The source script that has been loaded into a debuggee compartment.
    * @param aFunction Debugger.Object
    *        The function object that the ew code is part of.
    */
   onNewScript: function TA_onNewScript(aScript, aFunction) {
-    dumpn("Got a new script:" + aScript + ", url: " + aScript.url +
-          ", startLine: " + aScript.startLine + ", lineCount: " +
-          aScript.lineCount + ", strictMode: " + aScript.strictMode +
-          ", function: " + aFunction);
     // Use a sparse array for storing the scripts for each URL in order to
     // optimize retrieval. XXX: in case this is not fast enough for very large
     // files with too many scripts, we could sort the hash of script locations
     // or use a trie.
     if (!this._scripts[aScript.url]) {
       this._scripts[aScript.url] = [];
     }
     this._scripts[aScript.url][aScript.startLine] = aScript;
@@ -665,16 +750,17 @@ ThreadActor.prototype = {
 };
 
 ThreadActor.prototype.requestTypes = {
   "attach": ThreadActor.prototype.onAttach,
   "detach": ThreadActor.prototype.onDetach,
   "resume": ThreadActor.prototype.onResume,
   "clientEvaluate": ThreadActor.prototype.onClientEvaluate,
   "frames": ThreadActor.prototype.onFrames,
+  "interrupt": ThreadActor.prototype.onInterrupt,
   "releaseMany": ThreadActor.prototype.onReleaseMany,
   "setBreakpoint": ThreadActor.prototype.onSetBreakpoint,
   "scripts": ThreadActor.prototype.onScripts
 };
 
 
 /**
  * Creates a PauseActor.
@@ -1074,17 +1160,17 @@ BreakpointActor.prototype = {
       if (!packet) {
         return undefined;
       }
       // TODO: add the rest of the breakpoints on that line.
       packet.why = { type: "breakpoint", actors: [ this.actorID ] };
       this.conn.send(packet);
       return this.threadActor._nest();
     } catch(e) {
-      dumpn("Got an exception during hit: " + e + ': ' + e.stack);
+      Cu.reportError("Got an exception during hit: " + e + ': ' + e.stack);
       return undefined;
     }
   },
 
   /**
    * Handle a protocol request to remove this breakpoint.
    *
    * @param aRequest object
@@ -1227,9 +1313,8 @@ EnvironmentActor.prototype = {
              bindings: this._bindings() };
   }
 };
 
 EnvironmentActor.prototype.requestTypes = {
   "assign": EnvironmentActor.prototype.onAssign,
   "bindings": EnvironmentActor.prototype.onBindings
 };
-
--- a/toolkit/devtools/debugger/server/dbg-server.js
+++ b/toolkit/devtools/debugger/server/dbg-server.js
@@ -427,17 +427,17 @@ DebuggerServerConnection.prototype = {
 
     var ret = null;
 
     // Dispatch the request to the actor.
     if (actor.requestTypes && actor.requestTypes[aPacket.type]) {
       try {
         ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket);
       } catch(e) {
-        dumpn(e);
+        Cu.reportError(e);
         ret = { error: "unknownError",
                 message: "An unknown error has occurred while processing request." };
       }
     } else {
       ret = { error: "unrecognizedPacketType",
               message: 'Actor "' + actor.actorID + '" does not recognize the packet type "' + aPacket.type + '"' };
     }
 
--- a/toolkit/devtools/debugger/tests/unit/test_breakpoint-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-01.js
@@ -41,18 +41,17 @@ function test_simple_breakpoint()
         bpClient.remove(function (aResponse) {
           gThreadClient.resume(function () {
             finishClient(gClient);
           });
         });
 
       });
       // Continue until the breakpoint is hit.
-      gThreadClient.resume(function () {
-      });
+      gThreadClient.resume();
 
     });
 
   });
 
   gDebuggee.eval("var line0 = Error().lineNumber;\n" +
                  "debugger;\n" +   // line0 + 1
                  "var a = 1;\n" +  // line0 + 2
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting breakpoints when the debuggee is running works.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient, "test-stack", function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_breakpoint_running();
+    });
+  });
+  do_test_pending();
+}
+
+function test_breakpoint_running()
+{
+  let path = getFilePath('test_breakpoint-01.js');
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "var a = 1;\n" +  // line0 + 1
+                 "var b = 2;\n");  // line0 + 2
+
+  // Setting the breakpoint later should interrupt the debuggee.
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    do_check_eq(aPacket.type, "paused");
+    do_check_eq(aPacket.why.type, "interrupted");
+  });
+
+  gThreadClient.setBreakpoint({ url: path, line: gDebuggee.line0 + 3}, function(aResponse) {
+    // Eval scripts don't stick around long enough for the breakpoint to be set,
+    // so just make sure we got the expected response from the actor.
+    do_check_eq(aResponse.error, "noScript");
+
+    do_execute_soon(function() {
+      finishClient(gClient);
+    });
+  });
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-03.js
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting a breakpoint in a line without code will skip forward.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_skip_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_skip_breakpoint()
+{
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-03.js');
+    let location = { url: path, line: gDebuggee.line0 + 3};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      // Check that the breakpoint has properly skipped forward one line.
+      do_check_eq(aResponse.actualLocation.url, location.url);
+      do_check_eq(aResponse.actualLocation.line, location.line + 1);
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.a, 1);
+        do_check_eq(gDebuggee.b, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function (aResponse) {
+          gThreadClient.resume(function () {
+            finishClient(gClient);
+          });
+        });
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "debugger;\n" +      // line0 + 1
+                 "var a = 1;\n" +     // line0 + 2
+                 "// A comment.\n" +  // line0 + 3
+                 "var b = 2;\n");     // line0 + 4
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-04.js
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting a breakpoint in a line in a child script works.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_child_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_child_breakpoint()
+{
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-04.js');
+    let location = { url: path, line: gDebuggee.line0 + 3};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      // actualLocation is not returned when breakpoints don't skip forward.
+      do_check_eq(aResponse.actualLocation, undefined);
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.a, 1);
+        do_check_eq(gDebuggee.b, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function (aResponse) {
+          gThreadClient.resume(function () {
+            finishClient(gClient);
+          });
+        });
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "function foo() {\n" + // line0 + 1
+                 "  this.a = 1;\n" +     // line0 + 2
+                 "  this.b = 2;\n" +     // line0 + 3
+                 "}\n" +                // line0 + 4
+                 "debugger;\n" +        // line0 + 5
+                 "foo();\n");           // line0 + 6
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-05.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting a breakpoint in a line without code in a child script
+ * will skip forward.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_child_skip_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_child_skip_breakpoint()
+{
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-05.js');
+    let location = { url: path, line: gDebuggee.line0 + 3};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      // Check that the breakpoint has properly skipped forward one line.
+      do_check_eq(aResponse.actualLocation.url, location.url);
+      do_check_eq(aResponse.actualLocation.line, location.line + 1);
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.a, 1);
+        do_check_eq(gDebuggee.b, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function (aResponse) {
+          gThreadClient.resume(function () {
+            finishClient(gClient);
+          });
+        });
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "function foo() {\n" + // line0 + 1
+                 "  this.a = 1;\n" +    // line0 + 2
+                 "  // A comment.\n" +  // line0 + 3
+                 "  this.b = 2;\n" +    // line0 + 4
+                 "}\n" +                // line0 + 5
+                 "debugger;\n" +        // line0 + 6
+                 "foo();\n");           // line0 + 7
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-06.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting a breakpoint in a line without code in a deeply-nested
+ * child script will skip forward.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_nested_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_nested_breakpoint()
+{
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-06.js');
+    let location = { url: path, line: gDebuggee.line0 + 5};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      // Check that the breakpoint has properly skipped forward one line.
+      do_check_eq(aResponse.actualLocation.url, location.url);
+      do_check_eq(aResponse.actualLocation.line, location.line + 1);
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.a, 1);
+        do_check_eq(gDebuggee.b, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function (aResponse) {
+          gThreadClient.resume(function () {
+            finishClient(gClient);
+          });
+        });
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "function foo() {\n" +     // line0 + 1
+                 "  function bar() {\n" +   // line0 + 2
+                 "    function baz() {\n" + // line0 + 3
+                 "      this.a = 1;\n" +    // line0 + 4
+                 "      // A comment.\n" +  // line0 + 5
+                 "      this.b = 2;\n" +    // line0 + 6
+                 "    }\n" +                // line0 + 7
+                 "    baz();\n" +           // line0 + 8
+                 "  }\n" +                  // line0 + 9
+                 "  bar();\n" +             // line0 + 10
+                 "}\n" +                    // line0 + 11
+                 "debugger;\n" +            // line0 + 12
+                 "foo();\n");               // line0 + 13
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-07.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting a breakpoint in a line without code in the second child
+ * script will skip forward.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_second_child_skip_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_second_child_skip_breakpoint()
+{
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-07.js');
+    let location = { url: path, line: gDebuggee.line0 + 6};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      // Check that the breakpoint has properly skipped forward one line.
+      do_check_eq(aResponse.actualLocation.url, location.url);
+      do_check_eq(aResponse.actualLocation.line, location.line + 1);
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.a, 1);
+        do_check_eq(gDebuggee.b, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function (aResponse) {
+          gThreadClient.resume(function () {
+            finishClient(gClient);
+          });
+        });
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "function foo() {\n" + // line0 + 1
+                 "  bar();\n" +         // line0 + 2
+                 "}\n" +                // line0 + 3
+                 "function bar() {\n" + // line0 + 4
+                 "  this.a = 1;\n" +    // line0 + 5
+                 "  // A comment.\n" +  // line0 + 6
+                 "  this.b = 2;\n" +    // line0 + 7
+                 "}\n" +                // line0 + 8
+                 "debugger;\n" +        // line0 + 9
+                 "foo();\n");           // line0 + 10
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-08.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting a breakpoint in a line without code in a child script
+ * will skip forward, in a file with two scripts.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_child_skip_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_child_skip_breakpoint()
+{
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-08.js');
+    let location = { url: path, line: gDebuggee.line0 + 3};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      // Check that the breakpoint has properly skipped forward one line.
+      do_check_eq(aResponse.actualLocation.url, location.url);
+      do_check_eq(aResponse.actualLocation.line, location.line + 1);
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.a, 1);
+        do_check_eq(gDebuggee.b, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function (aResponse) {
+          gThreadClient.resume(function () {
+            finishClient(gClient);
+          });
+        });
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "function foo() {\n" + // line0 + 1
+                 "  this.a = 1;\n" +    // line0 + 2
+                 "  // A comment.\n" +  // line0 + 3
+                 "  this.b = 2;\n" +    // line0 + 4
+                 "}\n");                // line0 + 5
+  gDebuggee.eval("var line1 = Error().lineNumber;\n" +
+                 "debugger;\n" +        // line1 + 1
+                 "foo();\n");           // line1 + 2
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-09.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that removing a breakpoint works.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_remove_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_remove_breakpoint()
+{
+  let done = false;
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-09.js');
+    let location = { url: path, line: gDebuggee.line0 + 1};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.a, undefined);
+
+        // Remove the breakpoint.
+        bpClient.remove(function (aResponse) {
+          done = true;
+          gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+            // The breakpoint should not be hit again.
+            gThreadClient.resume(function () {
+              do_check_true(false);
+            });
+          });
+          gThreadClient.resume();
+        });
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "function foo(stop) {\n" + // line0 + 1
+                 "  this.a = 1;\n" +        // line0 + 2
+                 "  if (stop) return;\n" +  // line0 + 3
+                 "  delete this.a;\n" +     // line0 + 4
+                 "  foo(true);\n" +         // line0 + 5
+                 "}\n" +                    // line0 + 6
+                 "debugger;\n" +            // line1 + 7
+                 "foo();\n");               // line1 + 8
+  if (!done) {
+    do_check_true(false);
+  }
+  finishClient(gClient);
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-10.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that setting a breakpoint in a line with multiple entry points
+ * triggers no matter which entry point we reach.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-stack");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function () {
+    attachTestGlobalClientAndResume(gClient,
+                                    "test-stack",
+                                    function (aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_child_breakpoint();
+    });
+  });
+  do_test_pending();
+}
+
+function test_child_breakpoint()
+{
+  gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+    let path = getFilePath('test_breakpoint-10.js');
+    let location = { url: path, line: gDebuggee.line0 + 3};
+    gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
+      // actualLocation is not returned when breakpoints don't skip forward.
+      do_check_eq(aResponse.actualLocation, undefined);
+      gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+        // Check the return value.
+        do_check_eq(aPacket.type, "paused");
+        do_check_eq(aPacket.why.type, "breakpoint");
+        do_check_eq(aPacket.why.actors[0], bpClient.actor);
+        // Check that the breakpoint worked.
+        do_check_eq(gDebuggee.i, 0);
+
+        gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
+          // Check the return value.
+          do_check_eq(aPacket.type, "paused");
+          do_check_eq(aPacket.why.type, "breakpoint");
+          do_check_eq(aPacket.why.actors[0], bpClient.actor);
+          // Check that the breakpoint worked.
+          do_check_eq(gDebuggee.i, 1);
+
+          // Remove the breakpoint.
+          bpClient.remove(function (aResponse) {
+            gThreadClient.resume(function () {
+              finishClient(gClient);
+            });
+          });
+        });
+
+        // Continue until the breakpoint is hit again.
+        gThreadClient.resume();
+
+      });
+      // Continue until the breakpoint is hit.
+      gThreadClient.resume();
+
+    });
+
+  });
+
+
+  gDebuggee.eval("var line0 = Error().lineNumber;\n" +
+                 "debugger;\n" +                      // line0 + 1
+                 "var a, i = 0;\n" +                  // line0 + 2
+                 "for (i = 1; i <= 2; i++) {\n" +     // line0 + 3
+                 "  a = i;\n" +                       // line0 + 4
+                 "}\n");                              // line0 + 5
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_interrupt.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var gClient;
+var gDebuggee;
+
+function run_test()
+{
+  DebuggerServer.addActors("resource://test/testactors.js");
+
+  DebuggerServer.init();
+  gDebuggee = testGlobal("test-1");
+  DebuggerServer.addTestGlobal(gDebuggee);
+
+  let transport = DebuggerServer.connectPipe();
+  gClient = new DebuggerClient(transport);
+  gClient.connect(function(aType, aTraits) {
+    getTestGlobalContext(gClient, "test-1", function(aContext) {
+      test_attach(aContext);
+    });
+  });
+  do_test_pending();
+}
+
+function test_attach(aContext)
+{
+  gClient.attachThread(aContext.actor, function(aResponse, aThreadClient) {
+    do_check_eq(aThreadClient.paused, true);
+    aThreadClient.resume(function() {
+      test_interrupt();
+    });
+  });
+}
+
+function test_interrupt()
+{
+  do_check_eq(gClient.activeThread.paused, false);
+  gClient.activeThread.interrupt(function(aResponse) {
+    do_check_eq(gClient.activeThread.paused, true);
+    gClient.activeThread.resume(function() {
+      do_check_eq(gClient.activeThread.paused, false);
+      cleanup();
+    });
+  });
+}
+
+function cleanup()
+{
+  gClient.addListener("closed", function(aEvent) {
+    do_test_finished();
+  });
+  gClient.close();
+}
+
--- a/toolkit/devtools/debugger/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/debugger/tests/unit/xpcshell.ini
@@ -29,13 +29,23 @@ tail =
 [test_frameclient-02.js]
 [test_nativewrappers.js]
 [test_eval-01.js]
 [test_eval-02.js]
 [test_eval-03.js]
 [test_eval-04.js]
 [test_eval-05.js]
 [test_breakpoint-01.js]
+[test_breakpoint-02.js]
+[test_breakpoint-03.js]
+[test_breakpoint-04.js]
+[test_breakpoint-05.js]
+[test_breakpoint-06.js]
+[test_breakpoint-07.js]
+[test_breakpoint-08.js]
+[test_breakpoint-09.js]
+[test_breakpoint-10.js]
 [test_listscripts-01.js]
 [test_objectgrips-01.js]
 [test_objectgrips-02.js]
 [test_objectgrips-03.js]
 [test_objectgrips-04.js]
+[test_interrupt.js]
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -1,17 +1,11 @@
-#
-# ***** BEGIN LICENSE BLOCK *****
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
-# Contributor(s):
-#   Shawn Wilsher <me@shawnwilsher.com>
-#
-# ***** END LICENSE BLOCK *****
 
 DEPTH     = ../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk