Merge central and inbound
authorMarco Bonardo <mbonardo@mozilla.com>
Tue, 13 Mar 2012 14:49:19 +0100
changeset 90139 d87ad51531b5c701fe5cefe04d58c6e11b27fb0e
parent 90138 c16f72c6237418540a1d8421f4b760f60aceb0d6 (current diff)
parent 90121 4b9fb42c0d52def41cd51c849920f38308baeb61 (diff)
child 90140 d381ce0baac06feb2ffcdfa2f3e63430d7505d3e
child 90160 a0df03570b26f5d0324459d3ec5b5f91bfe08603
child 90550 60ebef177e6d522e6d9a0095399d4cef1da6823e
push idunknown
push userunknown
push dateunknown
milestone13.0a1
Merge central and inbound
browser/base/content/newtab/toolbar.js
browser/themes/gnomestripe/newtab/strip.png
browser/themes/gnomestripe/newtab/toolbar.png
browser/themes/pinstripe/newtab/strip.png
browser/themes/pinstripe/newtab/toolbar.png
browser/themes/winstripe/newtab/strip.png
browser/themes/winstripe/newtab/toolbar.png
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -41,17 +41,17 @@ pref("toolkit.defaultChromeURI", "chrome
 pref("browser.chromeURL", "chrome://browser/content/");
 #ifdef MOZ_OFFICIAL_BRANDING
 pref("browser.homescreenURL", "file:///system/home/homescreen.html");
 #else
 pref("browser.homescreenURL", "file:///data/local/homescreen.html,file:///system/home/homescreen.html");
 #endif
 
 // URL for the dialer application.
-pref("dom.telephony.app.phone.url", "http://localhost:7777/data/local/apps/dialer/dialer.html http://localhost:7777/data/local/apps/homescreen/homescreen.html http://localhost:7777/apps/dialer/dialer.html http://localhost:7777/apps/homescreen/homescreen.html");
+pref("dom.telephony.app.phone.url", "http://localhost:7777/data/local/apps/dialer/dialer.html,http://localhost:7777/data/local/apps/homescreen/homescreen.html,http://localhost:7777/apps/dialer/dialer.html,http://localhost:7777/apps/homescreen/homescreen.html");
 
 // Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
 pref("browser.viewport.scaleRatio", -1);
 
 /* disable text selection */
 pref("browser.ignoreNativeFrameTextSelection", true);
 
 /* cache prefs */
@@ -439,8 +439,17 @@ pref("b2g.keys.menu.enabled", true);
 pref("b2g.keys.search.enabled", false);
 
 // Screen timeout in minutes
 pref("power.screen.timeout", 60);
 
 pref("full-screen-api.enabled", true);
 
 pref("media.volume.steps", 10);
+
+// Data connection settings. These will eventually live in the
+// navigator.settings API, or even in a database where we can look
+// it up automatically (bug 729440), but for this will have to do.
+pref("ril.data.enabled", false);
+pref("ril.data.roaming.enabled", false);
+pref("ril.data.apn", "");
+pref("ril.data.user", "");
+pref("ril.data.passwd", "");
--- a/browser/base/content/newtab/cells.js
+++ b/browser/base/content/newtab/cells.js
@@ -10,26 +10,24 @@
  * aren't handled here.
  */
 function Cell(aGrid, aNode) {
   this._grid = aGrid;
   this._node = aNode;
   this._node._newtabCell = this;
 
   // Register drag-and-drop event handlers.
-  ["DragEnter", "DragOver", "DragExit", "Drop"].forEach(function (aType) {
-    let method = "on" + aType;
-    this[method] = this[method].bind(this);
-    this._node.addEventListener(aType.toLowerCase(), this[method], false);
+  ["dragenter", "dragover", "dragexit", "drop"].forEach(function (aType) {
+    this._node.addEventListener(aType, this, false);
   }, this);
 }
 
 Cell.prototype = {
   /**
-   *
+   * The grid.
    */
   _grid: null,
 
   /**
    * The cell's DOM node.
    */
   get node() this._node,
 
@@ -92,46 +90,32 @@ Cell.prototype = {
    * Checks whether the cell contains a site (is empty).
    * @return Whether the cell is empty.
    */
   isEmpty: function Cell_isEmpty() {
     return !this.site;
   },
 
   /**
-   * Event handler for the 'dragenter' event.
-   * @param aEvent The dragenter event.
-   */
-  onDragEnter: function Cell_onDragEnter(aEvent) {
-    if (gDrag.isValid(aEvent)) {
-      aEvent.preventDefault();
-      gDrop.enter(this, aEvent);
-    }
-  },
-
-  /**
-   * Event handler for the 'dragover' event.
-   * @param aEvent The dragover event.
+   * Handles all cell events.
    */
-  onDragOver: function Cell_onDragOver(aEvent) {
-    if (gDrag.isValid(aEvent))
-      aEvent.preventDefault();
-  },
+  handleEvent: function Cell_handleEvent(aEvent) {
+    if (aEvent.type != "dragexit" && !gDrag.isValid(aEvent))
+      return;
 
-  /**
-   * Event handler for the 'dragexit' event.
-   * @param aEvent The dragexit event.
-   */
-  onDragExit: function Cell_onDragExit(aEvent) {
-    gDrop.exit(this, aEvent);
-  },
-
-  /**
-   * Event handler for the 'drop' event.
-   * @param aEvent The drop event.
-   */
-  onDrop: function Cell_onDrop(aEvent) {
-    if (gDrag.isValid(aEvent)) {
-      aEvent.preventDefault();
-      gDrop.drop(this, aEvent);
+    switch (aEvent.type) {
+      case "dragenter":
+        aEvent.preventDefault();
+        gDrop.enter(this, aEvent);
+        break;
+      case "dragover":
+        aEvent.preventDefault();
+        break;
+      case "dragexit":
+        gDrop.exit(this, aEvent);
+        break;
+      case "drop":
+        aEvent.preventDefault();
+        gDrop.drop(this, aEvent);
+        break;
     }
   }
 };
--- a/browser/base/content/newtab/drag.js
+++ b/browser/base/content/newtab/drag.js
@@ -31,21 +31,21 @@ let gDrag = {
   /**
    * Start a new drag operation.
    * @param aSite The site that's being dragged.
    * @param aEvent The 'dragstart' event.
    */
   start: function Drag_start(aSite, aEvent) {
     this._draggedSite = aSite;
 
-    // Prevent moz-transform for left, top.
-    aSite.node.setAttribute("dragged", "true");
-
-    // Make sure the dragged site is floating above the grid.
-    aSite.node.setAttribute("ontop", "true");
+    // Mark nodes as being dragged.
+    let selector = ".newtab-site, .newtab-control, .newtab-thumbnail";
+    let nodes = aSite.node.parentNode.querySelectorAll(selector);
+    for (let i = 0; i < nodes.length; i++)
+      nodes[i].setAttribute("dragged", "true");
 
     this._setDragData(aSite, aEvent);
 
     // Store the cursor offset.
     let node = aSite.node;
     let rect = node.getBoundingClientRect();
     this._offsetX = aEvent.clientX - rect.left;
     this._offsetY = aEvent.clientY - rect.top;
@@ -83,35 +83,38 @@ let gDrag = {
   },
 
   /**
    * Ends the current drag operation.
    * @param aSite The site that's being dragged.
    * @param aEvent The 'dragend' event.
    */
   end: function Drag_end(aSite, aEvent) {
-    aSite.node.removeAttribute("dragged");
+    let nodes = aSite.node.parentNode.querySelectorAll("[dragged]");
+    for (let i = 0; i < nodes.length; i++)
+      nodes[i].removeAttribute("dragged");
 
     // Slide the dragged site back into its cell (may be the old or the new cell).
-    gTransformation.slideSiteTo(aSite, aSite.cell, {
-      unfreeze: true,
-      callback: function () aSite.node.removeAttribute("ontop")
-    });
+    gTransformation.slideSiteTo(aSite, aSite.cell, {unfreeze: true});
 
     this._draggedSite = null;
   },
 
   /**
    * Checks whether we're responsible for a given drag event.
    * @param aEvent The drag event to check.
    * @return Whether we should handle this drag and drop operation.
    */
   isValid: function Drag_isValid(aEvent) {
     let dt = aEvent.dataTransfer;
-    return dt && dt.types.contains("text/x-moz-url");
+    let mimeType = "text/x-moz-url";
+
+    // Check that the drag data is non-empty.
+    // Can happen when dragging places folders.
+    return dt && dt.types.contains(mimeType) && dt.getData(mimeType);
   },
 
   /**
    * Initializes the drag data for the current drag operation.
    * @param aSite The site that's being dragged.
    * @param aEvent The 'dragstart' event.
    */
   _setDragData: function Drag_setDragData(aSite, aEvent) {
@@ -123,18 +126,18 @@ let gDrag = {
     dt.setData("text/plain", url);
     dt.setData("text/uri-list", url);
     dt.setData("text/x-moz-url", url + "\n" + title);
     dt.setData("text/html", "<a href=\"" + url + "\">" + url + "</a>");
 
     // Create and use an empty drag element. We don't want to use the default
     // drag image with its default opacity.
     let dragElement = document.createElementNS(HTML_NAMESPACE, "div");
-    dragElement.classList.add("drag-element");
-    let body = document.getElementById("body");
-    body.appendChild(dragElement);
+    dragElement.classList.add("newtab-drag");
+    let scrollbox = document.getElementById("newtab-scrollbox");
+    scrollbox.appendChild(dragElement);
     dt.setDragImage(dragElement, 0, 0);
 
     // After the 'dragstart' event has been processed we can remove the
     // temporary drag element from the DOM.
-    setTimeout(function () body.removeChild(dragElement), 0);
+    setTimeout(function () scrollbox.removeChild(dragElement), 0);
   }
 };
--- a/browser/base/content/newtab/dropTargetShim.js
+++ b/browser/base/content/newtab/dropTargetShim.js
@@ -21,52 +21,60 @@ let gDropTargetShim = {
   _lastDropTarget: null,
 
   /**
    * Initializes the drop target shim.
    */
   init: function DropTargetShim_init() {
     let node = gGrid.node;
 
-    this._dragover = this._dragover.bind(this);
+    // Add drag event handlers.
+    node.addEventListener("dragstart", this, true);
+    node.addEventListener("dragend", this, true);
+  },
 
-    // Add drag event handlers.
-    node.addEventListener("dragstart", this._start.bind(this), true);
-    // XXX bug 505521 - Don't listen for drag, it's useless at the moment.
-    //node.addEventListener("drag", this._drag.bind(this), false);
-    node.addEventListener("dragend", this._end.bind(this), true);
+  /**
+   * Handles all shim events.
+   */
+  handleEvent: function DropTargetShim_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "dragstart":
+        this._start(aEvent);
+        break;
+      case "dragover":
+        this._dragover(aEvent);
+        break;
+      case "dragend":
+        this._end(aEvent);
+        break;
+    }
   },
 
   /**
    * Handles the 'dragstart' event.
    * @param aEvent The 'dragstart' event.
    */
   _start: function DropTargetShim_start(aEvent) {
-    if (aEvent.target.classList.contains("site")) {
+    if (aEvent.target.classList.contains("newtab-link")) {
       gGrid.lock();
 
       // XXX bug 505521 - Listen for dragover on the document.
-      document.documentElement.addEventListener("dragover", this._dragover, false);
+      document.documentElement.addEventListener("dragover", this, false);
     }
   },
 
   /**
    * Handles the 'drag' event and determines the current drop target.
    * @param aEvent The 'drag' event.
    */
   _drag: function DropTargetShim_drag(aEvent) {
     // Let's see if we find a drop target.
     let target = this._findDropTarget(aEvent);
 
-    if (target == this._lastDropTarget) {
-      // XXX bug 505521 - Don't fire dragover for now (causes recursion).
-      /*if (target)
-        // The last drop target is valid and didn't change.
-        this._dispatchEvent(aEvent, "dragover", target);*/
-    } else {
+    if (target != this._lastDropTarget) {
       if (this._lastDropTarget)
         // We left the last drop target.
         this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
 
       if (target)
         // We're now hovering a (new) drop target.
         this._dispatchEvent(aEvent, "dragenter", target);
 
@@ -79,17 +87,17 @@ let gDropTargetShim = {
   },
 
   /**
    * Handles the 'dragover' event as long as bug 505521 isn't fixed to get
    * current mouse cursor coordinates while dragging.
    * @param aEvent The 'dragover' event.
    */
   _dragover: function DropTargetShim_dragover(aEvent) {
-    let sourceNode = aEvent.dataTransfer.mozSourceNode;
+    let sourceNode = aEvent.dataTransfer.mozSourceNode.parentNode;
     gDrag.drag(sourceNode._newtabSite, aEvent);
 
     this._drag(aEvent);
   },
 
   /**
    * Handles the 'dragend' event.
    * @param aEvent The 'dragend' event.
@@ -112,17 +120,17 @@ let gDropTargetShim = {
       // Clean up.
       this._lastDropTarget = null;
       this._cellPositions = null;
     }
 
     gGrid.unlock();
 
     // XXX bug 505521 - Remove the document's dragover listener.
-    document.documentElement.removeEventListener("dragover", this._dragover, false);
+    document.documentElement.removeEventListener("dragover", this, false);
   },
 
   /**
    * Determines the current drop target by matching the dragged site's position
    * against all cells in the grid.
    * @return The currently hovered drop target or null.
    */
   _findDropTarget: function DropTargetShim_findDropTarget() {
--- a/browser/base/content/newtab/grid.js
+++ b/browser/base/content/newtab/grid.js
@@ -19,17 +19,17 @@ let gGrid = {
    */
   _siteFragment: null,
 
   /**
    * All cells contained in the grid.
    */
   get cells() {
     let cells = [];
-    let children = this.node.querySelectorAll("li");
+    let children = this.node.querySelectorAll(".newtab-cell");
     for (let i = 0; i < children.length; i++)
       cells.push(new Cell(this, children[i]));
 
     // Replace the getter with our cached value.
     Object.defineProperty(this, "cells", {value: cells, enumerable: true});
 
     return cells;
   },
@@ -38,18 +38,18 @@ let gGrid = {
    * All sites contained in the grid's cells. Sites may be empty.
    */
   get sites() [cell.site for each (cell in this.cells)],
 
   /**
    * Initializes the grid.
    * @param aSelector The query selector of the grid.
    */
-  init: function Grid_init(aSelector) {
-    this._node = document.querySelector(aSelector);
+  init: function Grid_init() {
+    this._node = document.getElementById("newtab-grid");
     this._createSiteFragment();
     this._draw();
   },
 
   /**
    * Creates a new site in the grid.
    * @param aLink The new site's link.
    * @param aCell The cell that will contain the new site.
@@ -91,31 +91,30 @@ let gGrid = {
   unlock: function Grid_unlock() {
     this.node.removeAttribute("locked");
   },
 
   /**
    * Creates the DOM fragment that is re-used when creating sites.
    */
   _createSiteFragment: function Grid_createSiteFragment() {
-    let site = document.createElementNS(HTML_NAMESPACE, "a");
-    site.classList.add("site");
+    let site = document.createElementNS(HTML_NAMESPACE, "div");
+    site.classList.add("newtab-site");
     site.setAttribute("draggable", "true");
 
     // Create the site's inner HTML code.
     site.innerHTML =
-      '<img class="site-img" width="' + THUMB_WIDTH +'" ' +
-      ' height="' + THUMB_HEIGHT + '" alt=""/>' +
-      '<span class="site-title"/>' +
-      '<span class="site-strip">' +
-      '  <input class="button strip-button strip-button-pin" type="button"' +
-      '   tabindex="-1" title="' + newTabString("pin") + '"/>' +
-      '  <input class="button strip-button strip-button-block" type="button"' +
-      '   tabindex="-1" title="' + newTabString("block") + '"/>' +
-      '</span>';
+      '<a class="newtab-link">' +
+      '  <span class="newtab-thumbnail"/>' +
+      '  <span class="newtab-title"/>' +
+      '</a>' +
+      '<input type="button" title="' + newTabString("pin") + '"' +
+      '       class="newtab-control newtab-control-pin"/>' +
+      '<input type="button" title="' + newTabString("block") + '"' +
+      '       class="newtab-control newtab-control-block"/>';
 
     this._siteFragment = document.createDocumentFragment();
     this._siteFragment.appendChild(site);
   },
 
   /**
    * Draws the grid, creates all sites and puts them into their cells.
    */
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -1,173 +1,186 @@
 :root {
-  -moz-appearance: none;
-}
-
-#scrollbox:not([page-disabled]) {
-  overflow: auto;
+  -moz-user-focus: normal;
 }
 
-#body {
-  position: relative;
-  margin: 0;
-  min-width: 675px;
-  -moz-user-select: none;
-}
-
-.button {
+input[type=button] {
   cursor: pointer;
 }
 
-/* TOOLBAR */
-#toolbar {
-  position: absolute;
+/* SCROLLBOX */
+#newtab-scrollbox {
+  display: -moz-box;
+  position: relative;
+  -moz-box-flex: 1;
 }
 
-#toolbar[page-disabled] {
-  position: fixed;
+#newtab-scrollbox:not([page-disabled]) {
+  overflow: auto;
 }
 
-#toolbar:-moz-locale-dir(rtl) {
-  left: 8px;
+/* TOGGLE */
+#newtab-toggle {
+  position: absolute;
+  top: 12px;
+  right: 12px;
+}
+
+#newtab-toggle:-moz-locale-dir(rtl) {
+  left: 12px;
   right: auto;
 }
 
-.toolbar-button {
-  position: absolute;
-  cursor: pointer;
-  -moz-transition: opacity 200ms ease-out;
+/* MARGINS */
+#newtab-vertical-margin {
+  display: -moz-box;
+  position: relative;
+  -moz-box-flex: 1;
+  -moz-box-orient: vertical;
+}
+
+#newtab-margin-top {
+  min-height: 50px;
+  max-height: 80px;
+  -moz-box-flex: 1;
+}
+
+#newtab-margin-bottom {
+  min-height: 40px;
+  max-height: 100px;
+  -moz-box-flex: 1;
 }
 
-#toolbar-button-show,
-#toolbar-button-reset {
+#newtab-horizontal-margin {
+  display: -moz-box;
+  -moz-box-flex: 5;
+}
+
+.newtab-side-margin {
+  min-width: 40px;
+  max-width: 300px;
+  -moz-box-flex: 1;
+}
+
+/* GRID */
+#newtab-grid {
+  display: -moz-box;
+  -moz-box-flex: 5;
+  -moz-box-orient: vertical;
+  min-width: 600px;
+  min-height: 400px;
+  -moz-transition: 100ms ease-out;
+  -moz-transition-property: opacity;
+}
+
+#newtab-grid[page-disabled] {
   opacity: 0;
+}
+
+#newtab-grid[locked],
+#newtab-grid[page-disabled] {
   pointer-events: none;
 }
 
-#toolbar-button-reset[modified],
-#toolbar-button-show[page-disabled] {
-  opacity: 1;
-  pointer-events: auto;
-}
-
-#toolbar-button-hide[page-disabled],
-#toolbar-button-reset[page-disabled] {
-  opacity: 0;
-  pointer-events: none;
-}
-
-/* GRID */
-#grid {
-  width: 637px;
-  height: 411px;
-  overflow: hidden;
-  list-style-type: none;
-  -moz-transition: opacity 200ms ease-out;
-}
-
-#grid[page-disabled] {
-  opacity: 0;
-}
-
-#grid[page-disabled],
-#grid[locked] {
-  pointer-events: none;
+/* ROWS */
+.newtab-row {
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-direction: normal;
+  -moz-box-flex: 1;
 }
 
 /* CELLS */
-.cell {
-  float: left;
-  width: 201px;
-  height: 127px;
-  margin-bottom: 15px;
-  -moz-margin-end: 16px;
-}
-
-.cell:-moz-locale-dir(rtl) {
-  float: right;
-}
-
-.cell:nth-child(3n+3) {
-  -moz-margin-end: 0;
+.newtab-cell {
+  display: -moz-box;
+  -moz-box-flex: 1;
 }
 
 /* SITES */
-.site {
-  display: block;
+.newtab-site {
   position: relative;
-  width: 201px;
-  height: 127px;
+  -moz-box-flex: 1;
+  -moz-transition: 100ms ease-out;
+  -moz-transition-property: top, left, opacity;
 }
 
-.site[frozen] {
+.newtab-site[frozen] {
   position: absolute;
   pointer-events: none;
 }
 
-.site[ontop] {
+.newtab-site[dragged] {
+  -moz-transition-property: none;
   z-index: 10;
 }
 
-/* SITE IMAGE */
-.site-img {
-  display: block;
-  opacity: 0.75;
-  -moz-transition: opacity 200ms ease-out;
+/* LINK + THUMBNAILS */
+.newtab-link,
+.newtab-thumbnail {
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
 }
 
-.site:hover > .site-img,
-.site[ontop] > .site-img,
-.site:-moz-focusring > .site-img {
+.newtab-thumbnail {
+  opacity: .8;
+  -moz-transition: opacity 100ms ease-out;
+}
+
+.newtab-thumbnail[dragged],
+.newtab-link:-moz-focusring > .newtab-thumbnail,
+.newtab-site:hover > .newtab-link > .newtab-thumbnail {
   opacity: 1;
 }
 
-.site-img[loading] {
-  display: none;
-}
-
-/* SITE TITLE */
-.site-title {
+/* TITLES */
+.newtab-title {
   position: absolute;
   left: 0;
+  right: 0;
   bottom: 0;
+  white-space: nowrap;
   overflow: hidden;
+  text-overflow: ellipsis;
 }
 
-/* SITE STRIP */
-.site-strip {
+/* CONTROLS */
+.newtab-control {
   position: absolute;
-  left: 0;
-  top: 0;
-  width: 195px;
-  height: 17px;
-  overflow: hidden;
+  top: 4px;
   opacity: 0;
-  -moz-transition: opacity 200ms ease-out;
+  -moz-transition: opacity 100ms ease-out;
 }
 
-.site:hover:not([frozen]) > .site-strip {
+.newtab-control:-moz-focusring,
+.newtab-site:hover > .newtab-control {
   opacity: 1;
 }
 
-.strip-button-pin,
-.strip-button-block:-moz-locale-dir(rtl) {
-  float: left;
+.newtab-control[dragged] {
+  opacity: 0 !important;
 }
 
-.strip-button-block,
-.strip-button-pin:-moz-locale-dir(rtl) {
-  float: right;
+.newtab-control-pin:-moz-locale-dir(ltr),
+.newtab-control-block:-moz-locale-dir(rtl) {
+  left: 4px;
+}
+
+.newtab-control-block:-moz-locale-dir(ltr),
+.newtab-control-pin:-moz-locale-dir(rtl) {
+  right: 4px;
 }
 
 /* DRAG & DROP */
 
 /*
  * This is just a temporary drag element used for dataTransfer.setDragImage()
  * so that we can use custom drag images and elements. It needs an opacity of
  * 0.01 so that the core code detects that it's in fact a visible element.
  */
-.drag-element {
+.newtab-drag {
   width: 1px;
   height: 1px;
   background-color: #fff;
   opacity: 0.01;
 }
--- a/browser/base/content/newtab/newTab.js
+++ b/browser/base/content/newtab/newTab.js
@@ -25,26 +25,23 @@ let {
 XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
   return Services.strings.
     createBundle("chrome://browser/locale/newTab.properties");
 });
 
 function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
 
 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
-const THUMB_WIDTH = 201;
-const THUMB_HEIGHT = 127;
 
 #include batch.js
 #include transformations.js
 #include page.js
-#include toolbar.js
 #include grid.js
 #include cells.js
 #include sites.js
 #include drag.js
 #include drop.js
 #include dropTargetShim.js
 #include dropPreview.js
 #include updater.js
 
 // Everything is loaded. Initialize the New Tab Page.
-gPage.init("#toolbar", "#grid");
+gPage.init();
--- a/browser/base/content/newtab/newTab.xul
+++ b/browser/base/content/newtab/newTab.xul
@@ -1,40 +1,56 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 # 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/.
 
-<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/newtab/newTab.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/newtab/newTab.css" type="text/css"?>
 
 <!DOCTYPE window [
   <!ENTITY % newTabDTD SYSTEM "chrome://browser/locale/newTab.dtd">
   %newTabDTD;
 ]>
 
-<xul:window xmlns="http://www.w3.org/1999/xhtml"
+<xul:window id="newtab-window" xmlns="http://www.w3.org/1999/xhtml"
             xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            disablefastfind="true" title="&newtab.pageTitle;">
-  <xul:vbox id="scrollbox" flex="1" title=" ">
-    <body id="body">
-      <div id="toolbar">
-        <input class="button toolbar-button" id="toolbar-button-show"
-               type="button" title="&newtab.show;"/>
-        <input class="button toolbar-button" id="toolbar-button-hide"
-               type="button" title="&newtab.hide;"/>
-        <input class="button toolbar-button" id="toolbar-button-reset"
-               type="button" title="&newtab.reset;"/>
+            xul:disablefastfind="true" xul:title="&newtab.pageTitle;">
+
+  <div id="newtab-scrollbox">
+
+    <div id="newtab-vertical-margin">
+      <div id="newtab-margin-top"/>
+
+      <div id="newtab-horizontal-margin">
+        <div class="newtab-side-margin"/>
+
+        <div id="newtab-grid">
+          <div class="newtab-row">
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+          </div>
+          <div class="newtab-row">
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+          </div>
+          <div class="newtab-row">
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+          </div>
+        </div>
+
+        <div class="newtab-side-margin"/>
       </div>
 
-      <ul id="grid">
-        <li class="cell"/><li class="cell"/><li class="cell"/>
-        <li class="cell"/><li class="cell"/><li class="cell"/>
-        <li class="cell"/><li class="cell"/><li class="cell"/>
-      </ul>
+      <div id="newtab-margin-bottom"/>
+    </div>
+    <input id="newtab-toggle" type="button"/>
+  </div>
 
-      <xul:script type="text/javascript;version=1.8"
-                  src="chrome://browser/content/newtab/newTab.js"/>
-    </body>
-  </xul:vbox>
+  <xul:script type="text/javascript;version=1.8"
+              src="chrome://browser/content/newtab/newTab.js"/>
 </xul:window>
--- a/browser/base/content/newtab/page.js
+++ b/browser/base/content/newtab/page.js
@@ -6,35 +6,34 @@
 
 /**
  * This singleton represents the whole 'New Tab Page' and takes care of
  * initializing all its components.
  */
 let gPage = {
   /**
    * Initializes the page.
-   * @param aToolbarSelector The query selector for the page toolbar.
-   * @param aGridSelector The query selector for the grid.
    */
-  init: function Page_init(aToolbarSelector, aGridSelector) {
-    gToolbar.init(aToolbarSelector);
-    this._gridSelector = aGridSelector;
-
+  init: function Page_init() {
     // Add ourselves to the list of pages to receive notifications.
     gAllPages.register(this);
 
     // Listen for 'unload' to unregister this page.
-    function unload() { gAllPages.unregister(this); }
-    addEventListener("unload", unload.bind(this), false);
+    addEventListener("unload", this, false);
+
+    // Listen for toggle button clicks.
+    let button = document.getElementById("newtab-toggle");
+    button.addEventListener("click", this, false);
 
     // Check if the new tab feature is enabled.
-    if (gAllPages.enabled)
+    let enabled = gAllPages.enabled;
+    if (enabled)
       this._init();
-    else
-      this._updateAttributes(false);
+
+    this._updateAttributes(enabled);
   },
 
   /**
    * Listens for notifications specific to this page.
    */
   observe: function Page_observe() {
     let enabled = gAllPages.enabled;
     this._updateAttributes(enabled);
@@ -43,132 +42,82 @@ let gPage = {
     if (enabled)
       this._init();
   },
 
   /**
    * Updates the whole page and the grid when the storage has changed.
    */
   update: function Page_update() {
-    this.updateModifiedFlag();
     gGrid.refresh();
   },
 
   /**
-   * Checks if the page is modified and sets the CSS class accordingly
-   */
-  updateModifiedFlag: function Page_updateModifiedFlag() {
-    let node = document.getElementById("toolbar-button-reset");
-    let modified = this._isModified();
-
-    if (modified)
-      node.setAttribute("modified", "true");
-    else
-      node.removeAttribute("modified");
-
-    this._updateTabIndices(gAllPages.enabled, modified);
-  },
-
-  /**
    * Internally initializes the page. This runs only when/if the feature
    * is/gets enabled.
    */
   _init: function Page_init() {
     if (this._initialized)
       return;
 
     this._initialized = true;
 
     gLinks.populateCache(function () {
-      // Check if the grid is modified.
-      this.updateModifiedFlag();
-
       // Initialize and render the grid.
-      gGrid.init(this._gridSelector);
+      gGrid.init();
 
       // Initialize the drop target shim.
       gDropTargetShim.init();
 
 #ifdef XP_MACOSX
       // Workaround to prevent a delay on MacOSX due to a slow drop animation.
-      document.addEventListener("dragover", this.onDragOver, false);
-      document.addEventListener("drop", this.onDrop, false);
+      document.addEventListener("dragover", this, false);
+      document.addEventListener("drop", this, false);
 #endif
     }.bind(this));
   },
 
   /**
    * Updates the 'page-disabled' attributes of the respective DOM nodes.
-   * @param aValue Whether to set or remove attributes.
+   * @param aValue Whether the New Tab Page is enabled or not.
    */
   _updateAttributes: function Page_updateAttributes(aValue) {
-    let nodes = document.querySelectorAll("#grid, #scrollbox, #toolbar, .toolbar-button");
+    let selector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid";
+    let nodes = document.querySelectorAll(selector);
 
     // Set the nodes' states.
     for (let i = 0; i < nodes.length; i++) {
       let node = nodes[i];
       if (aValue)
         node.removeAttribute("page-disabled");
       else
         node.setAttribute("page-disabled", "true");
     }
 
-    this._updateTabIndices(aValue, this._isModified());
-  },
-
-  /**
-   * Checks whether the page is modified.
-   * @return Whether the page is modified or not.
-   */
-  _isModified: function Page_isModified() {
-    // The page is considered modified only if sites have been removed.
-    return !gBlockedLinks.isEmpty();
+    // Update the toggle button's title.
+    let toggle = document.getElementById("newtab-toggle");
+    toggle.setAttribute("title", newTabString(aValue ? "hide" : "show"));
   },
 
   /**
-   * Updates the tab indices of focusable elements.
-   * @param aEnabled Whether the page is currently enabled.
-   * @param aModified Whether the page is currently modified.
+   * Handles all page events.
    */
-  _updateTabIndices: function Page_updateTabIndices(aEnabled, aModified) {
-    function setFocusable(aNode, aFocusable) {
-      if (aFocusable)
-        aNode.removeAttribute("tabindex");
-      else
-        aNode.setAttribute("tabindex", "-1");
-    }
-
-    // Sites and the 'hide' button are always focusable when the grid is shown.
-    let nodes = document.querySelectorAll(".site, #toolbar-button-hide");
-    for (let i = 0; i < nodes.length; i++)
-      setFocusable(nodes[i], aEnabled);
-
-    // The 'show' button is focusable when the grid is hidden.
-    let btnShow = document.getElementById("toolbar-button-show");
-    setFocusable(btnShow, !aEnabled);
-
-    // The 'reset' button is focusable when the grid is shown and modified.
-    let btnReset = document.getElementById("toolbar-button-reset");
-    setFocusable(btnReset, aEnabled && aModified);
-  },
-
-  /**
-   * Handles the 'dragover' event. Workaround to prevent a delay on MacOSX
-   * due to a slow drop animation.
-   * @param aEvent The 'dragover' event.
-   */
-  onDragOver: function Page_onDragOver(aEvent) {
-    if (gDrag.isValid(aEvent) && gDrag.draggedSite)
-      aEvent.preventDefault();
-  },
-
-  /**
-   * Handles the 'drop' event. Workaround to prevent a delay on MacOSX due to
-   * a slow drop animation.
-   * @param aEvent The 'drop' event.
-   */
-  onDrop: function Page_onDrop(aEvent) {
-    if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
-      aEvent.preventDefault();
-      aEvent.stopPropagation();
+  handleEvent: function Page_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "unload":
+        gAllPages.unregister(this);
+        break;
+      case "click":
+        gAllPages.enabled = !gAllPages.enabled;
+        break;
+      case "dragover":
+        if (gDrag.isValid(aEvent) && gDrag.draggedSite)
+          aEvent.preventDefault();
+        break;
+      case "drop":
+        if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
+          aEvent.preventDefault();
+          aEvent.stopPropagation();
+        }
+        break;
     }
   }
 };
--- a/browser/base/content/newtab/sites.js
+++ b/browser/base/content/newtab/sites.js
@@ -86,17 +86,16 @@ Site.prototype = {
    */
   block: function Site_block(aCallback) {
     if (gBlockedLinks.isBlocked(this._link)) {
       if (aCallback)
         aCallback();
     } else {
       gBlockedLinks.block(this._link);
       gUpdater.updateGrid(aCallback);
-      gPage.updateModifiedFlag();
     }
   },
 
   /**
    * Gets the DOM node specified by the given query selector.
    * @param aSelector The query selector.
    * @return The DOM node we found.
    */
@@ -105,110 +104,76 @@ Site.prototype = {
   },
 
   /**
    * Updates attributes for all nodes which status depends on this site being
    * pinned or unpinned.
    * @param aPinned Whether this site is now pinned or unpinned.
    */
   _updateAttributes: function (aPinned) {
-    let buttonPin = this._querySelector(".strip-button-pin");
+    let control = this._querySelector(".newtab-control-pin");
 
     if (aPinned) {
-      this.node.setAttribute("pinned", true);
-      buttonPin.setAttribute("title", newTabString("unpin"));
+      control.setAttribute("pinned", true);
+      control.setAttribute("title", newTabString("unpin"));
     } else {
-      this.node.removeAttribute("pinned");
-      buttonPin.setAttribute("title", newTabString("pin"));
+      control.removeAttribute("pinned");
+      control.setAttribute("title", newTabString("pin"));
     }
   },
 
   /**
    * Renders the site's data (fills the HTML fragment).
    */
   _render: function Site_render() {
     let title = this.title || this.url;
-    this.node.setAttribute("title", title);
-    this.node.setAttribute("href", this.url);
-    this._querySelector(".site-title").textContent = title;
+    let link = this._querySelector(".newtab-link");
+    link.setAttribute("title", title);
+    link.setAttribute("href", this.url);
+    this._querySelector(".newtab-title").textContent = title;
 
     if (this.isPinned())
       this._updateAttributes(true);
 
-    this._renderThumbnail();
-  },
-
-  /**
-   * Renders the site's thumbnail.
-   */
-  _renderThumbnail: function Site_renderThumbnail() {
-    let img = this._querySelector(".site-img")
-    img.setAttribute("alt", this.title || this.url);
-    img.setAttribute("loading", "true");
-
-    // Wait until the image has loaded.
-    img.addEventListener("load", function onLoad() {
-      img.removeEventListener("load", onLoad, false);
-      img.removeAttribute("loading");
-    }, false);
-
-    // Set the thumbnail url.
-    img.setAttribute("src", PageThumbs.getThumbnailURL(this.url));
+    let thumbnailURL = PageThumbs.getThumbnailURL(this.url);
+    let thumbnail = this._querySelector(".newtab-thumbnail");
+    thumbnail.style.backgroundImage = "url(" + thumbnailURL + ")";
   },
 
   /**
    * Adds event handlers for the site and its buttons.
    */
   _addEventHandlers: function Site_addEventHandlers() {
     // Register drag-and-drop event handlers.
-    ["DragStart", /*"Drag",*/ "DragEnd"].forEach(function (aType) {
-      let method = "_on" + aType;
-      this[method] = this[method].bind(this);
-      this._node.addEventListener(aType.toLowerCase(), this[method], false);
-    }, this);
-
-    let self = this;
-
-    function pin(aEvent) {
-      if (aEvent)
-        aEvent.preventDefault();
+    this._node.addEventListener("dragstart", this, false);
+    this._node.addEventListener("dragend", this, false);
 
-      if (self.isPinned())
-        self.unpin();
-      else
-        self.pin();
-    }
-
-    function block(aEvent) {
-      if (aEvent)
-        aEvent.preventDefault();
-
-      self.block();
-    }
-
-    this._querySelector(".strip-button-pin").addEventListener("click", pin, false);
-    this._querySelector(".strip-button-block").addEventListener("click", block, false);
+    let controls = this.node.querySelectorAll(".newtab-control");
+    for (let i = 0; i < controls.length; i++)
+      controls[i].addEventListener("click", this, false);
   },
 
   /**
-   * Event handler for the 'dragstart' event.
-   * @param aEvent The drag event.
+   * Handles all site events.
    */
-  _onDragStart: function Site_onDragStart(aEvent) {
-    gDrag.start(this, aEvent);
-  },
-
-  /**
-   * Event handler for the 'drag' event.
-   * @param aEvent The drag event.
-  */
-  _onDrag: function Site_onDrag(aEvent) {
-    gDrag.drag(this, aEvent);
-  },
-
-  /**
-   * Event handler for the 'dragend' event.
-   * @param aEvent The drag event.
-   */
-  _onDragEnd: function Site_onDragEnd(aEvent) {
-    gDrag.end(this, aEvent);
+  handleEvent: function Site_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "click":
+        aEvent.preventDefault();
+        if (aEvent.target.classList.contains("newtab-control-block"))
+          this.block();
+        else if (this.isPinned())
+          this.unpin();
+        else
+          this.pin();
+        break;
+      case "dragstart":
+        gDrag.start(this, aEvent);
+        break;
+      case "drag":
+        gDrag.drag(this, aEvent);
+        break;
+      case "dragend":
+        gDrag.end(this, aEvent);
+        break;
+    }
   }
 };
deleted file mode 100644
--- a/browser/base/content/newtab/toolbar.js
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifdef 0
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-#endif
-
-/**
- * This singleton represents the page's toolbar that allows to enable/disable
- * the 'New Tab Page' feature and to reset the whole page.
- */
-let gToolbar = {
-  /**
-   * Initializes the toolbar.
-   * @param aSelector The query selector of the toolbar.
-   */
-  init: function Toolbar_init(aSelector) {
-    this._node = document.querySelector(aSelector);
-    let buttons = this._node.querySelectorAll("input");
-
-    // Listen for 'click' events on the toolbar buttons.
-    ["show", "hide", "reset"].forEach(function (aType, aIndex) {
-      let self = this;
-      let button = buttons[aIndex];
-      let handler = function () self[aType]();
-
-      button.addEventListener("click", handler, false);
-
-#ifdef XP_MACOSX
-      // Per default buttons lose focus after being clicked on Mac OS X.
-      // So when the URL bar has focus and a toolbar button is clicked the
-      // URL bar regains focus and the history pops up. We need to prevent
-      // that by explicitly removing its focus.
-      button.addEventListener("mousedown", function () {
-        window.focus();
-      }, false);
-#endif
-    }, this);
-  },
-
-  /**
-   * Enables the 'New Tab Page' feature.
-   */
-  show: function Toolbar_show() {
-    this._passButtonFocus("show", "hide");
-    gAllPages.enabled = true;
-  },
-
-  /**
-   * Disables the 'New Tab Page' feature.
-   */
-  hide: function Toolbar_hide() {
-    this._passButtonFocus("hide", "show");
-    gAllPages.enabled = false;
-  },
-
-  /**
-   * Resets the whole page and forces it to re-render its content.
-   * @param aCallback The callback to call when the page has been reset.
-   */
-  reset: function Toolbar_reset(aCallback) {
-    this._passButtonFocus("reset", "hide");
-    let node = gGrid.node;
-
-    // animate the page reset
-    gTransformation.fadeNodeOut(node, function () {
-      NewTabUtils.reset();
-
-      gLinks.populateCache(function () {
-        gAllPages.update();
-
-        // Without the setTimeout() we have a strange flicker.
-        setTimeout(function () gTransformation.fadeNodeIn(node, aCallback));
-      }, true);
-    });
-  },
-
-  /**
-   * Passes the focus from the current button to the next.
-   * @param aCurrent The button that currently has focus.
-   * @param aNext The button that is focused next.
-   */
-  _passButtonFocus: function Toolbar_passButtonFocus(aCurrent, aNext) {
-    if (document.querySelector("#toolbar-button-" + aCurrent + ":-moz-focusring"))
-      document.getElementById("toolbar-button-" + aNext).focus();
-  }
-};
-
--- a/browser/base/content/newtab/transformations.js
+++ b/browser/base/content/newtab/transformations.js
@@ -6,16 +6,34 @@
 
 /**
  * This singleton allows to transform the grid by repositioning a site's node
  * in the DOM and by showing or hiding the node. It additionally provides
  * convenience methods to work with a site's DOM node.
  */
 let gTransformation = {
   /**
+   * Returns the width of the left and top border of a cell. We need to take it
+   * into account when measuring and comparing site and cell positions.
+   */
+  get _cellBorderWidths() {
+    let cstyle = window.getComputedStyle(gGrid.cells[0].node, null);
+    let widths = {
+      left: parseInt(cstyle.getPropertyValue("border-left-width")),
+      top: parseInt(cstyle.getPropertyValue("border-top-width"))
+    };
+
+    // Cache this value, overwrite the getter.
+    Object.defineProperty(this, "_cellBorderWidths",
+                          {value: widths, enumerable: true});
+
+    return widths;
+  },
+
+  /**
    * Gets a DOM node's position.
    * @param aNode The DOM node.
    * @return A Rect instance with the position.
    */
   getNodePosition: function Transformation_getNodePosition(aNode) {
     let {left, top, width, height} = aNode.getBoundingClientRect();
     return new Rect(left + scrollX, top + scrollY, width, height);
   },
@@ -75,27 +93,38 @@ let gTransformation = {
     style.left = left + "px";
   },
 
   /**
    * Freezes a site in its current position by positioning it absolute.
    * @param aSite The site to freeze.
    */
   freezeSitePosition: function Transformation_freezeSitePosition(aSite) {
+    if (this._isFrozen(aSite))
+      return;
+
+    let style = aSite.node.style;
+    let comp = getComputedStyle(aSite.node, null);
+    style.width = comp.getPropertyValue("width")
+    style.height = comp.getPropertyValue("height");
+
     aSite.node.setAttribute("frozen", "true");
     this.setSitePosition(aSite, this.getNodePosition(aSite.node));
   },
 
   /**
    * Unfreezes a site by removing its absolute positioning.
    * @param aSite The site to unfreeze.
    */
   unfreezeSitePosition: function Transformation_unfreezeSitePosition(aSite) {
+    if (!this._isFrozen(aSite))
+      return;
+
     let style = aSite.node.style;
-    style.left = style.top = "";
+    style.left = style.top = style.width = style.height = "";
     aSite.node.removeAttribute("frozen");
   },
 
   /**
    * Slides the given site to the target node's position.
    * @param aSite The site to move.
    * @param aTarget The slide target.
    * @param aOptions Set of options (see below).
@@ -112,18 +141,23 @@ let gTransformation = {
     function finish() {
       if (aOptions && aOptions.unfreeze)
         self.unfreezeSitePosition(aSite);
 
       if (callback)
         callback();
     }
 
+    // We need to take the width of a cell's border into account.
+    targetPosition.left += this._cellBorderWidths.left;
+    targetPosition.top += this._cellBorderWidths.top;
+
     // Nothing to do here if the positions already match.
-    if (currentPosition.equals(targetPosition)) {
+    if (currentPosition.left == targetPosition.left &&
+        currentPosition.top == targetPosition.top) {
       finish();
     } else {
       this.setSitePosition(aSite, targetPosition);
       this._whenTransitionEnded(aSite.node, finish);
     }
   },
 
   /**
@@ -217,10 +251,19 @@ let gTransformation = {
    * Moves a site to the cell with the given index.
    * @param aSite The site to move.
    * @param aIndex The target cell's index.
    * @param aOptions Options that are directly passed to slideSiteTo().
    */
   _moveSite: function Transformation_moveSite(aSite, aIndex, aOptions) {
     this.freezeSitePosition(aSite);
     this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions);
+  },
+
+  /**
+   * Checks whether a site is currently frozen.
+   * @param aSite The site to check.
+   * @return Whether the given site is frozen.
+   */
+  _isFrozen: function Transformation_isFrozen(aSite) {
+    return aSite.node.hasAttribute("frozen");
   }
 };
--- a/browser/base/content/test/newtab/Makefile.in
+++ b/browser/base/content/test/newtab/Makefile.in
@@ -18,14 +18,15 @@ include $(topsrcdir)/config/rules.mk
 	browser_newtab_drop_preview.js \
 	browser_newtab_private_browsing.js \
 	browser_newtab_reset.js \
 	browser_newtab_tabsync.js \
 	browser_newtab_unpin.js \
 	browser_newtab_bug722273.js \
 	browser_newtab_bug723102.js \
 	browser_newtab_bug723121.js \
+	browser_newtab_bug725996.js \
 	browser_newtab_bug734043.js \
 	head.js \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/base/content/test/newtab/browser_newtab_bug723102.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug723102.js
@@ -7,11 +7,12 @@ function runTests() {
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   let firstTab = gBrowser.selectedTab;
 
   yield addNewTabPageTab();
   gBrowser.removeTab(firstTab);
 
-  cw.gToolbar.hide();
+  ok(NewTabUtils.allPages.enabled, true, "page is enabled");
+  NewTabUtils.allPages.enabled = false;
   ok(cw.gGrid.node.hasAttribute("page-disabled"), "page is disabled");
 }
--- a/browser/base/content/test/newtab/browser_newtab_bug723121.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug723121.js
@@ -5,25 +5,29 @@ function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGridLocked(false, "grid is unlocked");
 
   let cell = cells[0].node;
   let site = cells[0].site.node;
+  let link = site.querySelector(".newtab-link");
 
-  sendDragEvent(site, "dragstart");
+  sendDragEvent(link, "dragstart");
   checkGridLocked(true, "grid is now locked");
 
-  sendDragEvent(site, "dragend");
+  sendDragEvent(link, "dragend");
   checkGridLocked(false, "grid isn't locked anymore");
 
   sendDragEvent(cell, "dragstart");
   checkGridLocked(false, "grid isn't locked - dragstart was ignored");
+
+  sendDragEvent(site, "dragstart");
+  checkGridLocked(false, "grid isn't locked - dragstart was ignored");
 }
 
 function checkGridLocked(aLocked, aMessage) {
   is(cw.gGrid.node.hasAttribute("locked"), aLocked, aMessage);
 }
 
 function sendDragEvent(aNode, aType) {
   let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug725996.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function runTests() {
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  let cell = cells[0].node;
+
+  sendDropEvent(cell, "about:blank#99\nblank");
+  is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
+     "first cell is pinned and contains the dropped site");
+
+  yield whenPagesUpdated();
+  checkGrid("99p,0,1,2,3,4,5,6,7");
+
+  sendDropEvent(cell, "");
+  is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
+     "first cell is still pinned with the site we dropped before");
+}
+
+function sendDropEvent(aNode, aData) {
+  let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
+  let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
+
+  let dataTransfer = {
+    mozUserCancelled: false,
+    setData: function () null,
+    setDragImage: function () null,
+    getData: function () aData,
+
+    types: {
+      contains: function (aType) aType == "text/x-moz-url"
+    },
+
+    mozGetDataAt: function (aType, aIndex) {
+      if (aIndex || aType != "text/x-moz-url")
+        return null;
+
+      return aData;
+    },
+  };
+
+  let event = cw.document.createEvent("DragEvents");
+  event.initDragEvent("drop", true, true, cw, 0, 0, 0, 0, 0,
+                      false, false, false, false, 0, null, dataTransfer);
+
+  windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
+}
--- a/browser/base/content/test/newtab/browser_newtab_bug734043.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug734043.js
@@ -1,19 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function runTests() {
+  // TODO Bug 735166 - Intermittent timeout in browser_newtab_bug734043.js
+  return;
+
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
 
   let receivedError = false;
-  let block = cw.document.querySelector(".strip-button-block");
+  let block = cw.document.querySelector(".newtab-control-block");
 
   function onError() {
     receivedError = true;
   }
 
   cw.addEventListener("error", onError);
 
   for (let i = 0; i < 3; i++) {
--- a/browser/base/content/test/newtab/browser_newtab_disable.js
+++ b/browser/base/content/test/newtab/browser_newtab_disable.js
@@ -10,25 +10,25 @@ function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   let gridNode = cw.gGrid.node;
 
   ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
 
-  cw.gToolbar.hide();
+  NewTabUtils.allPages.enabled = false;
   ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
 
   let oldGridNode = cw.gGrid.node;
 
   // create a second new tage page and make sure it's disabled. enable it
   // again and check if the former page gets enabled as well.
   yield addNewTabPageTab();
   ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
 
   // check that no sites have been rendered
   is(0, cw.document.querySelectorAll(".site").length, "no sites have been rendered");
 
-  cw.gToolbar.show();
+  NewTabUtils.allPages.enabled = true;
   ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
   ok(!oldGridNode.hasAttribute("page-disabled"), "old page is not disabled");
 }
--- a/browser/base/content/test/newtab/browser_newtab_reset.js
+++ b/browser/base/content/test/newtab/browser_newtab_reset.js
@@ -1,15 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /*
  * These tests make sure that resetting the 'New Tage Page' works as expected.
  */
 function runTests() {
+  // Disabled until bug 716543 is fixed.
+  return;
+
   // create a new tab page and check its modified state after blocking a site
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   let resetButton = cw.document.getElementById("toolbar-button-reset");
 
   checkGrid("0,1,2,3,4,5,6,7,8");
--- a/browser/base/content/test/newtab/browser_newtab_tabsync.js
+++ b/browser/base/content/test/newtab/browser_newtab_tabsync.js
@@ -3,16 +3,19 @@
 
 /*
  * These tests make sure that all changes that are made to a specific
  * 'New Tab Page' are synchronized with all other open 'New Tab Pages'
  * automatically. All about:newtab pages should always be in the same
  * state.
  */
 function runTests() {
+  // Disabled until bug 716543 is fixed.
+  return;
+
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks(",1");
 
   yield addNewTabPageTab();
   checkGrid("0,1p,2,3,4,5,6,7,8");
 
   let resetButton = cw.document.getElementById("toolbar-button-reset");
   ok(!resetButton.hasAttribute("modified"), "page is not modified");
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -183,17 +183,17 @@ function checkGrid(aSitesPattern, aSites
     // Check the site's url.
     if (site.url != "about:blank#" + num) {
       valid = false;
       is(site.url, "about:blank#" + num, "cell#" + index + " has the wrong url");
     }
 
     let shouldBePinned = /p$/.test(id);
     let cellContainsPinned = site.isPinned();
-    let cssClassPinned = site.node && site.node.hasAttribute("pinned");
+    let cssClassPinned = site.node && site.node.querySelector(".newtab-control-pin").hasAttribute("pinned");
 
     // Check if the site should be and is pinned.
     if (shouldBePinned) {
       if (!cellContainsPinned) {
         valid = false;
         ok(false, "expected cell#" + index + " to be pinned");
       } else if (!cssClassPinned) {
         valid = false;
@@ -265,15 +265,20 @@ function simulateDrop(aDropTarget, aDrag
   if (aDragSource)
     cw.gDrag.end(aDragSource.site);
 }
 
 /**
  * Resumes testing when all pages have been updated.
  */
 function whenPagesUpdated() {
-  NewTabUtils.allPages.register({
+  let page = {
     update: function () {
       NewTabUtils.allPages.unregister(this);
       executeSoon(TestRunner.next);
     }
+  };
+
+  NewTabUtils.allPages.register(page);
+  registerCleanupFunction(function () {
+    NewTabUtils.allPages.unregister(page);
   });
 }
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -39,17 +39,33 @@
 #
 # ***** END LICENSE BLOCK *****
 
 // Services = object with smart getters for common XPCOM services
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "BROWSER_NEW_TAB_URL", function () {
-  return Services.prefs.getCharPref("browser.newtab.url") || "about:blank";
+  const PREF = "browser.newtab.url";
+
+  function getNewTabPageURL() {
+    return Services.prefs.getCharPref(PREF) || "about:blank";
+  }
+
+  function update() {
+    BROWSER_NEW_TAB_URL = getNewTabPageURL();
+  }
+
+  Services.prefs.addObserver(PREF, update, false);
+  addEventListener("unload", function onUnload() {
+    removeEventListener("unload", onUnload);
+    Services.prefs.removeObserver(PREF, update);
+  });
+
+  return getNewTabPageURL();
 });
 
 var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
 
 var gBidiUI = false;
 
 /**
  * Determines whether the given url is considered a special URL for new tabs.
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -13,25 +13,25 @@ const Ci = Components.interfaces;
 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
 
 /**
  * The default width for page thumbnails.
  *
  * Hint: This is the default value because the 'New Tab Page' is the only
  *       client for now.
  */
-const THUMBNAIL_WIDTH = 201;
+const THUMBNAIL_WIDTH = 400;
 
 /**
  * The default height for page thumbnails.
  *
  * Hint: This is the default value because the 'New Tab Page' is the only
  *       client for now.
  */
-const THUMBNAIL_HEIGHT = 127;
+const THUMBNAIL_HEIGHT = 225;
 
 /**
  * The default background color for page thumbnails.
  */
 const THUMBNAIL_BG_COLOR = "#fff";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -66,17 +66,17 @@ include $(topsrcdir)/config/rules.mk
 	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 \
 	browser_dbg_update-editor-mode.js \
-	browser_dbg_select-line.js \
+	$(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \
 	browser_dbg_clean-exit.js \
 	browser_dbg_bug723069_editor-breakpoints.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
 	browser_dbg_displayName.js \
 	head.js \
 	$(NULL)
 
 _BROWSER_TEST_PAGES = \
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -19,16 +19,17 @@
    - The Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2011
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Rob Campbell <robcee@mozilla.com> (original author)
    -   Mihai Sucan <mihai.sucan@gmail.com>
    -   Erik Vold <erikvvold@gmail.com>
+   -   Mark Capella <markcapella@twcny.rr.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
--- a/browser/devtools/sourceeditor/orion/Makefile.dryice.js
+++ b/browser/devtools/sourceeditor/orion/Makefile.dryice.js
@@ -48,16 +48,17 @@ copy({
     ORION_EDITOR + "/orion/textview/global.js",
     ORION_EDITOR + "/orion/textview/eventTarget.js",
     ORION_EDITOR + "/orion/editor/regex.js",
     ORION_EDITOR + "/orion/textview/keyBinding.js",
     ORION_EDITOR + "/orion/textview/annotations.js",
     ORION_EDITOR + "/orion/textview/rulers.js",
     ORION_EDITOR + "/orion/textview/undoStack.js",
     ORION_EDITOR + "/orion/textview/textModel.js",
+    ORION_EDITOR + "/orion/textview/projectionTextModel.js",
     ORION_EDITOR + "/orion/textview/tooltip.js",
     ORION_EDITOR + "/orion/textview/textView.js",
     ORION_EDITOR + "/orion/textview/textDND.js",
     ORION_EDITOR + "/orion/editor/htmlGrammar.js",
     ORION_EDITOR + "/orion/editor/textMateStyler.js",
     ORION_EDITOR + "/examples/textview/textStyler.js",
   ],
   dest: js_src,
--- a/browser/devtools/sourceeditor/orion/README
+++ b/browser/devtools/sourceeditor/orion/README
@@ -17,16 +17,20 @@ Orion version: git clone from 2012-01-26
 
   + patches for Eclipse Bug 370606 - Problems with UndoStack and deletions at
                                      the beginning of the document
     http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=cec71bddaf32251c34d3728df5da13c130d14f33
     http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=3ce24b94f1d8103b16b9cf16f2f50a6302d43b18
     http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=27177e9a3dc70c20b4877e3eab3adfff1d56e342
     see https://bugs.eclipse.org/bugs/show_bug.cgi?id=370606
 
+  + patch for Mozilla Bug 730532 - remove CSS2Properties aliases for MozOpacity
+                                   and MozOutline*
+    see https://bugzilla.mozilla.org/show_bug.cgi?id=730532#c3
+
 # License
 
 The following files are licensed according to the contents in the LICENSE
 file:
   orion.js
   orion.css
 
 # Theming
--- a/browser/devtools/sourceeditor/orion/orion.js
+++ b/browser/devtools/sourceeditor/orion/orion.js
@@ -2565,16 +2565,600 @@ define("orion/textview/textModel", ['ori
 });/*******************************************************************************
  * @license
  * Copyright (c) 2010, 2011 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials are made 
  * available under the terms of the Eclipse Public License v1.0 
  * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
  * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
  * 
+ * Contributors: 
+ *		Felipe Heidrich (IBM Corporation) - initial API and implementation
+ *		Silenio Quarti (IBM Corporation) - initial API and implementation
+ ******************************************************************************/
+
+/*global define */
+
+define("orion/textview/projectionTextModel", ['orion/textview/textModel', 'orion/textview/eventTarget'], function(mTextModel, mEventTarget) {
+
+	/**
+	 * @class This object represents a projection range. A projection specifies a
+	 * range of text and the replacement text. The range of text is relative to the
+	 * base text model associated to a projection model.
+	 * <p>
+	 * <b>See:</b><br/>
+	 * {@link orion.textview.ProjectionTextModel}<br/>
+	 * {@link orion.textview.ProjectionTextModel#addProjection}<br/>
+	 * </p>		 
+	 * @name orion.textview.Projection
+	 * 
+	 * @property {Number} start The start offset of the projection range. 
+	 * @property {Number} end The end offset of the projection range. This offset is exclusive.
+	 * @property {String|orion.textview.TextModel} [text=""] The projection text to be inserted
+	 */
+	/**
+	 * Constructs a new <code>ProjectionTextModel</code> based on the specified <code>TextModel</code>.
+	 *
+	 * @param {orion.textview.TextModel} baseModel The base text model.
+	 *
+	 * @name orion.textview.ProjectionTextModel
+	 * @class The <code>ProjectionTextModel</code> represents a projection of its base text
+	 * model. Projection ranges can be added to the projection text model to hide and/or insert
+	 * ranges to the base text model.
+	 * <p>
+	 * The contents of the projection text model is modified when changes occur in the base model,
+	 * projection model or by calls to {@link #addProjection} and {@link #removeProjection}.
+	 * </p>
+	 * <p>
+	 * <b>See:</b><br/>
+	 * {@link orion.textview.TextView}<br/>
+	 * {@link orion.textview.TextModel}
+	 * {@link orion.textview.TextView#setModel}
+	 * </p>
+	 * @borrows orion.textview.EventTarget#addEventListener as #addEventListener
+	 * @borrows orion.textview.EventTarget#removeEventListener as #removeEventListener
+	 * @borrows orion.textview.EventTarget#dispatchEvent as #dispatchEvent
+	 */
+	function ProjectionTextModel(baseModel) {
+		this._model = baseModel;	/* Base Model */
+		this._projections = [];
+	}
+
+	ProjectionTextModel.prototype = /** @lends orion.textview.ProjectionTextModel.prototype */ {
+		/**
+		 * Adds a projection range to the model.
+		 * <p>
+		 * The model must notify the listeners before and after the the text is
+		 * changed by calling {@link #onChanging} and {@link #onChanged} respectively. 
+		 * </p>
+		 * @param {orion.textview.Projection} projection The projection range to be added.
+		 * 
+		 * @see #removeProjection
+		 */
+		addProjection: function(projection) {
+			if (!projection) {return;}
+			//start and end can't overlap any exist projection
+			var model = this._model, projections = this._projections;
+			projection._lineIndex = model.getLineAtOffset(projection.start);
+			projection._lineCount = model.getLineAtOffset(projection.end) - projection._lineIndex;
+			var text = projection.text;
+			if (!text) { text = ""; }
+			if (typeof text === "string") {
+				projection._model = new mTextModel.TextModel(text, model.getLineDelimiter());
+			} else {
+				projection._model = text;
+			}
+			var eventStart = this.mapOffset(projection.start, true);
+			var removedCharCount = projection.end - projection.start;
+			var removedLineCount = projection._lineCount;
+			var addedCharCount = projection._model.getCharCount();
+			var addedLineCount = projection._model.getLineCount() - 1;
+			var modelChangingEvent = {
+				type: "Changing",
+				text: projection._model.getText(),
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanging(modelChangingEvent);
+			var index = this._binarySearch(projections, projection.start);
+			projections.splice(index, 0, projection);
+			var modelChangedEvent = {
+				type: "Changed",
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanged(modelChangedEvent);
+		},
+		/**
+		 * Returns all projection ranges of this model.
+		 * 
+		 * @return {orion.textview.Projection[]} The projection ranges.
+		 * 
+		 * @see #addProjection
+		 */
+		getProjections: function() {
+			return this._projections.slice(0);
+		},
+		/**
+		 * Gets the base text model.
+		 *
+		 * @return {orion.textview.TextModel} The base text model.
+		 */
+		getBaseModel: function() {
+			return this._model;
+		},
+		/**
+		 * Maps offsets between the projection model and its base model.
+		 *
+		 * @param {Number} offset The offset to be mapped.
+		 * @param {Boolean} [baseOffset=false] <code>true</code> if <code>offset</code> is in base model and
+		 *	should be mapped to the projection model.
+		 * @return {Number} The mapped offset
+		 */
+		mapOffset: function(offset, baseOffset) {
+			var projections = this._projections, delta = 0, i, projection;
+			if (baseOffset) {
+				for (i = 0; i < projections.length; i++) {
+					projection = projections[i];
+					if (projection.start > offset) { break; }
+					if (projection.end > offset) { return -1; }
+					delta += projection._model.getCharCount() - (projection.end - projection.start);
+				}
+				return offset + delta;
+			}
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > offset - delta) { break; }
+				var charCount = projection._model.getCharCount();
+				if (projection.start + charCount > offset - delta) {
+					return -1;
+				}
+				delta += charCount - (projection.end - projection.start);
+			}
+			return offset - delta;
+		},
+		/**
+		 * Removes a projection range from the model.
+		 * <p>
+		 * The model must notify the listeners before and after the the text is
+		 * changed by calling {@link #onChanging} and {@link #onChanged} respectively. 
+		 * </p>
+		 * 
+		 * @param {orion.textview.Projection} projection The projection range to be removed.
+		 * 
+		 * @see #addProjection
+		 */
+		removeProjection: function(projection) {
+			//TODO remove listeners from model
+			var i, delta = 0;
+			for (i = 0; i < this._projections.length; i++) {
+				var p = this._projections[i];
+				if (p === projection) {
+					projection = p;
+					break;
+				}
+				delta += p._model.getCharCount() - (p.end - p.start);
+			}
+			if (i < this._projections.length) {
+				var model = this._model;
+				var eventStart = projection.start + delta;
+				var addedCharCount = projection.end - projection.start;
+				var addedLineCount = projection._lineCount;
+				var removedCharCount = projection._model.getCharCount();
+				var removedLineCount = projection._model.getLineCount() - 1;
+				var modelChangingEvent = {
+					type: "Changing",
+					text: model.getText(projection.start, projection.end),
+					start: eventStart,
+					removedCharCount: removedCharCount,
+					addedCharCount: addedCharCount,
+					removedLineCount: removedLineCount,
+					addedLineCount: addedLineCount
+				};
+				this.onChanging(modelChangingEvent);
+				this._projections.splice(i, 1);
+				var modelChangedEvent = {
+					type: "Changed",
+					start: eventStart,
+					removedCharCount: removedCharCount,
+					addedCharCount: addedCharCount,
+					removedLineCount: removedLineCount,
+					addedLineCount: addedLineCount
+				};
+				this.onChanged(modelChangedEvent);
+			}
+		},
+		/** @ignore */
+		_binarySearch: function (array, offset) {
+			var high = array.length, low = -1, index;
+			while (high - low > 1) {
+				index = Math.floor((high + low) / 2);
+				if (offset <= array[index].start) {
+					high = index;
+				} else {
+					low = index;
+				}
+			}
+			return high;
+		},
+		/**
+		 * @see orion.textview.TextModel#getCharCount
+		 */
+		getCharCount: function() {
+			var count = this._model.getCharCount(), projections = this._projections;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				count += projection._model.getCharCount() - (projection.end - projection.start);
+			}
+			return count;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLine
+		 */
+		getLine: function(lineIndex, includeDelimiter) {
+			if (lineIndex < 0) { return null; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, result = [], offset = 0, i, lineCount, projection;
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection._lineIndex >= lineIndex - delta) { break; }
+				lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount >= lineIndex - delta) {
+					var projectionLineIndex = lineIndex - (projection._lineIndex + delta);
+					if (projectionLineIndex < lineCount) {
+						return projection._model.getLine(projectionLineIndex, includeDelimiter);
+					} else {
+						result.push(projection._model.getLine(lineCount));
+					}
+				}
+				offset = projection.end;
+				delta += lineCount - projection._lineCount;
+			}
+			offset = Math.max(offset, model.getLineStart(lineIndex - delta));
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection._lineIndex > lineIndex - delta) { break; }
+				result.push(model.getText(offset, projection.start));
+				lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount > lineIndex - delta) {
+					result.push(projection._model.getLine(0, includeDelimiter));
+					return result.join("");
+				}
+				result.push(projection._model.getText());
+				offset = projection.end;
+				delta += lineCount - projection._lineCount;
+			}
+			var end = model.getLineEnd(lineIndex - delta, includeDelimiter);
+			if (offset < end) {
+				result.push(model.getText(offset, end));
+			}
+			return result.join("");
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineAtOffset
+		 */
+		getLineAtOffset: function(offset) {
+			var model = this._model, projections = this._projections;
+			var delta = 0, lineDelta = 0;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				if (projection.start > offset - delta) { break; }
+				var charCount = projection._model.getCharCount();
+				if (projection.start + charCount > offset - delta) {
+					var projectionOffset = offset - (projection.start + delta);
+					lineDelta += projection._model.getLineAtOffset(projectionOffset);
+					delta += projectionOffset;
+					break;
+				}
+				lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+				delta += charCount - (projection.end - projection.start);
+			}
+			return model.getLineAtOffset(offset - delta) + lineDelta;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineCount
+		 */
+		getLineCount: function() {
+			var model = this._model, projections = this._projections;
+			var count = model.getLineCount();
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				count += projection._model.getLineCount() - 1 - projection._lineCount;
+			}
+			return count;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineDelimiter
+		 */
+		getLineDelimiter: function() {
+			return this._model.getLineDelimiter();
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineEnd
+		 */
+		getLineEnd: function(lineIndex, includeDelimiter) {
+			if (lineIndex < 0) { return -1; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, offsetDelta = 0;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				if (projection._lineIndex > lineIndex - delta) { break; }
+				var lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount > lineIndex - delta) {
+					var projectionLineIndex = lineIndex - (projection._lineIndex + delta);
+					return projection._model.getLineEnd (projectionLineIndex, includeDelimiter) + projection.start + offsetDelta;
+				}
+				offsetDelta += projection._model.getCharCount() - (projection.end - projection.start);
+				delta += lineCount - projection._lineCount;
+			}
+			return model.getLineEnd(lineIndex - delta, includeDelimiter) + offsetDelta;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineStart
+		 */
+		getLineStart: function(lineIndex) {
+			if (lineIndex < 0) { return -1; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, offsetDelta = 0;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				if (projection._lineIndex >= lineIndex - delta) { break; }
+				var lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount >= lineIndex - delta) {
+					var projectionLineIndex = lineIndex - (projection._lineIndex + delta);
+					return projection._model.getLineStart (projectionLineIndex) + projection.start + offsetDelta;
+				}
+				offsetDelta += projection._model.getCharCount() - (projection.end - projection.start);
+				delta += lineCount - projection._lineCount;
+			}
+			return model.getLineStart(lineIndex - delta) + offsetDelta;
+		},
+		/**
+		 * @see orion.textview.TextModel#getText
+		 */
+		getText: function(start, end) {
+			if (start === undefined) { start = 0; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, result = [], i, projection, charCount;
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > start - delta) { break; }
+				charCount = projection._model.getCharCount();
+				if (projection.start + charCount > start - delta) {
+					if (end !== undefined && projection.start + charCount > end - delta) {
+						return projection._model.getText(start - (projection.start + delta), end - (projection.start + delta));
+					} else {
+						result.push(projection._model.getText(start - (projection.start + delta)));
+						start = projection.end + delta + charCount - (projection.end - projection.start);
+					}
+				}
+				delta += charCount - (projection.end - projection.start);
+			}
+			var offset = start - delta;
+			if (end !== undefined) {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					if (projection.start > end - delta) { break; }
+					result.push(model.getText(offset, projection.start));
+					charCount = projection._model.getCharCount();
+					if (projection.start + charCount > end - delta) {
+						result.push(projection._model.getText(0, end - (projection.start + delta)));
+						return result.join("");
+					}
+					result.push(projection._model.getText());
+					offset = projection.end;
+					delta += charCount - (projection.end - projection.start);
+				}
+				result.push(model.getText(offset, end - delta));
+			} else {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					result.push(model.getText(offset, projection.start));
+					result.push(projection._model.getText());
+					offset = projection.end;
+				}
+				result.push(model.getText(offset));
+			}
+			return result.join("");
+		},
+		/** @ignore */
+		_onChanging: function(text, start, removedCharCount, addedCharCount, removedLineCount, addedLineCount) {
+			var model = this._model, projections = this._projections, i, projection, delta = 0, lineDelta;
+			var end = start + removedCharCount;
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > start) { break; }
+				delta += projection._model.getCharCount() - (projection.end - projection.start);
+			}
+			/*TODO add stuff saved by setText*/
+			var mapStart = start + delta, rangeStart = i;
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > end) { break; }
+				delta += projection._model.getCharCount() - (projection.end - projection.start);
+				lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+			}
+			/*TODO add stuff saved by setText*/
+			var mapEnd = end + delta, rangeEnd = i;
+			this.onChanging(mapStart, mapEnd - mapStart, addedCharCount/*TODO add stuff saved by setText*/, removedLineCount + lineDelta/*TODO add stuff saved by setText*/, addedLineCount/*TODO add stuff saved by setText*/);
+			projections.splice(projections, rangeEnd - rangeStart);
+			var count = text.length - (mapEnd - mapStart);
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				projection.start += count;
+				projection.end += count;
+				projection._lineIndex = model.getLineAtOffset(projection.start);
+			}
+		},
+		/**
+		 * @see orion.textview.TextModel#onChanging
+		 */
+		onChanging: function(modelChangingEvent) {
+			return this.dispatchEvent(modelChangingEvent);
+		},
+		/**
+		 * @see orion.textview.TextModel#onChanged
+		 */
+		onChanged: function(modelChangedEvent) {
+			return this.dispatchEvent(modelChangedEvent);
+		},
+		/**
+		 * @see orion.textview.TextModel#setLineDelimiter
+		 */
+		setLineDelimiter: function(lineDelimiter) {
+			this._model.setLineDelimiter(lineDelimiter);
+		},
+		/**
+		 * @see orion.textview.TextModel#setText
+		 */
+		setText: function(text, start, end) {
+			if (text === undefined) { text = ""; }
+			if (start === undefined) { start = 0; }
+			var eventStart = start, eventEnd = end;
+			var model = this._model, projections = this._projections;
+			var delta = 0, lineDelta = 0, i, projection, charCount, startProjection, endProjection, startLineDelta = 0;
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > start - delta) { break; }
+				charCount = projection._model.getCharCount();
+				if (projection.start + charCount > start - delta) {
+					if (end !== undefined && projection.start + charCount > end - delta) {
+						projection._model.setText(text, start - (projection.start + delta), end - (projection.start + delta));
+						//TODO events - special case
+						return;
+					} else {
+						startLineDelta = projection._model.getLineCount() - 1 - projection._model.getLineAtOffset(start - (projection.start + delta));
+						startProjection = {
+							projection: projection,
+							start: start - (projection.start + delta)
+						};
+						start = projection.end + delta + charCount - (projection.end - projection.start);
+					}
+				}
+				lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+				delta += charCount - (projection.end - projection.start);
+			}
+			var mapStart = start - delta, rangeStart = i, startLine = model.getLineAtOffset(mapStart) + lineDelta - startLineDelta;
+			if (end !== undefined) {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					if (projection.start > end - delta) { break; }
+					charCount = projection._model.getCharCount();
+					if (projection.start + charCount > end - delta) {
+						lineDelta += projection._model.getLineAtOffset(end - (projection.start + delta));
+						charCount = end - (projection.start + delta);
+						end = projection.end + delta;
+						endProjection = {
+							projection: projection,
+							end: charCount
+						};
+						break;
+					}
+					lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+					delta += charCount - (projection.end - projection.start);
+				}
+			} else {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+					delta += projection._model.getCharCount() - (projection.end - projection.start);
+				}
+				end = eventEnd = model.getCharCount() + delta;
+			}
+			var mapEnd = end - delta, rangeEnd = i, endLine = model.getLineAtOffset(mapEnd) + lineDelta;
+			
+			//events
+			var removedCharCount = eventEnd - eventStart;
+			var removedLineCount = endLine - startLine;
+			var addedCharCount = text.length;
+			var addedLineCount = 0;
+			var cr = 0, lf = 0, index = 0;
+			while (true) {
+				if (cr !== -1 && cr <= index) { cr = text.indexOf("\r", index); }
+				if (lf !== -1 && lf <= index) { lf = text.indexOf("\n", index); }
+				if (lf === -1 && cr === -1) { break; }
+				if (cr !== -1 && lf !== -1) {
+					if (cr + 1 === lf) {
+						index = lf + 1;
+					} else {
+						index = (cr < lf ? cr : lf) + 1;
+					}
+				} else if (cr !== -1) {
+					index = cr + 1;
+				} else {
+					index = lf + 1;
+				}
+				addedLineCount++;
+			}
+			
+			var modelChangingEvent = {
+				type: "Changing",
+				text: text,
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanging(modelChangingEvent);
+			
+//			var changeLineCount = model.getLineAtOffset(mapEnd) - model.getLineAtOffset(mapStart) + addedLineCount;
+			model.setText(text, mapStart, mapEnd);
+			if (startProjection) {
+				projection = startProjection.projection;
+				projection._model.setText("", startProjection.start);
+			}		
+			if (endProjection) {
+				projection = endProjection.projection;
+				projection._model.setText("", 0, endProjection.end);
+				projection.start = projection.end;
+				projection._lineCount = 0;
+			}
+			projections.splice(rangeStart, rangeEnd - rangeStart);
+			var changeCount = text.length - (mapEnd - mapStart);
+			for (i = rangeEnd; i < projections.length; i++) {
+				projection = projections[i];
+				projection.start += changeCount;
+				projection.end += changeCount;
+//				if (projection._lineIndex + changeLineCount !== model.getLineAtOffset(projection.start)) {
+//					log("here");
+//				}
+				projection._lineIndex = model.getLineAtOffset(projection.start);
+//				projection._lineIndex += changeLineCount;
+			}
+			
+			var modelChangedEvent = {
+				type: "Changed",
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanged(modelChangedEvent);
+		}
+	};
+	mEventTarget.EventTarget.addMixin(ProjectionTextModel.prototype);
+
+	return {ProjectionTextModel: ProjectionTextModel};
+});
+/*******************************************************************************
+ * @license
+ * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made 
+ * available under the terms of the Eclipse Public License v1.0 
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+ * 
  * Contributors: IBM Corporation - initial API and implementation
  ******************************************************************************/
 
 /*global define setTimeout clearTimeout setInterval clearInterval Node */
 
 define("orion/textview/tooltip", ['orion/textview/textView', 'orion/textview/textModel', 'orion/textview/projectionTextModel'], function(mTextView, mTextModel, mProjectionTextModel) {
 
 	/** @private */
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -903,17 +903,18 @@ SourceEditor.prototype = {
     }
   },
 
   /**
    * Retrieve the list of Orion Annotations filtered by type for the given text range.
    *
    * @private
    * @param string aType
-   *        The annotation type to filter annotations for.
+   *        The annotation type to filter annotations for. Use one of the keys
+   *        in ORION_ANNOTATION_TYPES.
    * @param number aStart
    *        Offset from where to start finding the annotations.
    * @param number aEnd
    *        End offset for retrieving the annotations.
    * @return array
    *         The array of annotations, filtered by type, within the given text
    *         range.
    */
--- a/browser/devtools/sourceeditor/source-editor.jsm
+++ b/browser/devtools/sourceeditor/source-editor.jsm
@@ -263,34 +263,34 @@ SourceEditor.EVENTS = {
   FOCUS: "Focus",
 
   /**
    * The blur event is fired when the editor goes out of focus.
    */
   BLUR: "Blur",
 
   /**
-   * The MouseMove event is sent when the user moves the mouse over a line
-   * annotation. The event object properties:
+   * The MouseMove event is sent when the user moves the mouse over a line.
+   * The event object properties:
    *   - event - the DOM mousemove event object.
    *   - x and y - the mouse coordinates relative to the document being edited.
    */
   MOUSE_MOVE: "MouseMove",
 
   /**
-   * The MouseOver event is sent when the mouse pointer enters a line
-   * annotation. The event object properties:
+   * The MouseOver event is sent when the mouse pointer enters a line.
+   * The event object properties:
    *   - event - the DOM mouseover event object.
    *   - x and y - the mouse coordinates relative to the document being edited.
    */
   MOUSE_OVER: "MouseOver",
 
   /**
-   * This MouseOut event is sent when the mouse pointer exits a line
-   * annotation. The event object properties:
+   * This MouseOut event is sent when the mouse pointer exits a line.
+   * The event object properties:
    *   - event - the DOM mouseout event object.
    *   - x and y - the mouse coordinates relative to the document being edited.
    */
   MOUSE_OUT: "MouseOut",
 
   /**
    * The BreakpointChange event is fired when a new breakpoint is added or when
    * a breakpoint is removed - either through API use or through the editor UI.
--- a/browser/locales/en-US/chrome/browser/newTab.dtd
+++ b/browser/locales/en-US/chrome/browser/newTab.dtd
@@ -1,6 +1,2 @@
 <!-- These strings are used in the about:newtab page -->
 <!ENTITY newtab.pageTitle "New Tab">
-
-<!ENTITY newtab.show "Show the New Tab Page">
-<!ENTITY newtab.hide "Hide the New Tab Page">
-<!ENTITY newtab.reset "Reset the New Tab Page">
--- a/browser/locales/en-US/chrome/browser/newTab.properties
+++ b/browser/locales/en-US/chrome/browser/newTab.properties
@@ -1,3 +1,5 @@
 newtab.pin=Pin this site at its current position
 newtab.unpin=Unpin this site
 newtab.block=Remove this site
+newtab.show=Show the new tab page
+newtab.hide=Hide the new tab page
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -39,18 +39,18 @@ browser.jar:
   skin/classic/browser/feeds/feedIcon16.png           (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/subscribe.css            (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css         (feeds/subscribe-ui.css)
   skin/classic/browser/newtab/newTab.css              (newtab/newTab.css)
-  skin/classic/browser/newtab/strip.png               (newtab/strip.png)
-  skin/classic/browser/newtab/toolbar.png             (newtab/toolbar.png)
+  skin/classic/browser/newtab/controls.png            (newtab/controls.png)
+  skin/classic/browser/newtab/noise.png               (newtab/noise.png)
   skin/classic/browser/places/bookmarksMenu.png       (places/bookmarksMenu.png)
   skin/classic/browser/places/bookmarksToolbar.png    (places/bookmarksToolbar.png)
   skin/classic/browser/places/calendar.png            (places/calendar.png)
 * skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
   skin/classic/browser/places/livemark-item.png       (places/livemark-item.png)
   skin/classic/browser/places/pageStarred.png         (places/pageStarred.png)
   skin/classic/browser/places/starred48.png           (places/starred48.png)
   skin/classic/browser/places/unstarred48.png         (places/unstarred48.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14f382fbdd18a1209f3dcd63831014b5ad2fc428
GIT binary patch
literal 4180
zc$@)L5UcNrP)<h;3K|Lk000e1NJLTq008&^000;W1^@s6*Of4d00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyW3
z3po`Ymn>!g01wnjL_t(|+U=ZqR1{af$G^37(<}-RL{S73g}8w$#L2jfU~q|vxCPB(
zo=J>boWv||#JIeXmzNmFGh>XH%zK$Pal_}9NnD7EQAq^RxS$CHP(X}gBtnY>Z0g=S
ze{^-zOLbRuE64LD)H(Nb)wged&hOs({qDW>tFGd1-@c8&j$JvJHx2+Ve_D!`joB0`
zf5Le4M+Tsc|1ZpM-@ZLKpLVUnXLsuvfdBXW2f1-_<17sm0f@hOB+<9&?p?uTG6?{{
z7~_<G%rOAa>-EIo<3mp5pKJsm$;H~xHhvrb*UD#i>)8kYyDJC4X!&PHUU_~>l2#1>
zMm?VPn7@BOAOJKp+%X>An{`mDCdx1#fd24-F9ycP_1{1l<r$@%tA;5xl;e5Eb38p?
zcwv6>xQS;0m;jJAejC4yZw*@8eXSZoLqmPKckfXR0OjSEgFMkhdGrzi=;Px0W$r!r
zRapMF=R>?%4m>hAzGlK>qcQ=EkVh~oe`VztoVytI!{sYp@nd^L)C?Wa&n^FxP20i_
z9Qw*D{<tx}tNFKQ)7<jkKYcSStK^PX{Ir;Wnm2~HxBugdbzxsrG<wCK80A~@Qk;AK
zd&kPcwiZ@<#h)41x#q2r?)k0lKfYgl9_E*q=N12#VZ&<TCQfwAuiLsMtnu(+ulT;n
z$u)5^XFBp3W7K&~uTcX4UteES$Iy;V08m|h-Q<bJ+bm6di6jXpzby=Al);;F^4r2-
zB1r-OUzzE|FS%3|%qZYZDY;ao%0HNMEEtTzn{qJcm@0oqX?-wb6yB5_rS+=(eH9H}
z^Y>LWsPea8s19a~!JD%ELbWQtwf)DCpC3#qg*U~JpRdYq$jR}V-;k4|#0R4++oqk_
zo@f9N9T{$@tf=&_tf=&ljtn<=qFHC~sL03wN-0k$QC*gdO&Wphoa0V9p@gH9@==kI
z0Tq>%jW$UND__#UPZ-z_1!pfh>6Ag8Pb5|TjA@gxZO3jWT_TbyzgbeZfBujz*l_xq
zlip0V*iTjY&&7q})54#e?Fa6Q{R@Z3V0~_hSN3c1A6J_e{~;!m*L)ClK5cIHo=>SF
z|MxFUALm$As|Ene-dtD>AXGlAUjEiAnl(#+3lfp^lro-D3M~OnDOC(|N*ON^Ne@7<
z=|GS82?P6qQmP!}DtyM&6PHg<pA5#BVvwuaPlzgi!O$+Clw!lFA6un=o{I|wr3{}I
z-e?v6!Vxi`jA8xpA6kX)K1SU0B@O+5FZ|Z9f9=QH?2>1T=gdgbssTXqlTQZ(1_f~d
zV63YP@I<o)I3+}6jB!ju0~uu)moyTLGGyl*bGVLR93@0_>_7`&OMo!OkT|G67^OIQ
z=7L9jM%4qHGK!hgQ^6?3wjFys<P!~ih6M>-!5GDcf~y|!LACS`Fe|<j7^B#9zPc6o
z46lrc0izTj9xwK=f9@?n)cE%r;A(u*3ieY*oswr-H2`QI6yz5f8CeSe6+n<DnrLH~
zz!>AyMzFC-BVp-;6zfcW%&viqF+ri>0%MFL%soGGP#mZnqzQxKKp4ZxGliP@YBPA+
z)JY(+lcY_X1WGBgc7CRrPl@D~KQAEyl5GFnq2VBeBD3I%2YmMq{7ifpB)R{eiR%PH
zC^nzJuAQ$E;PXfHw%R{`L@WrU*l@ha1HS$FeQVLnh>8eD#g(gAz3wBInpVCf+4q0D
zWy>J+=mB#1GU`{Ya;bT1fA2MG;NPnk8cIu1^u`-5HFtcaK~Jj&0KNu;DI_GM2>@=~
zxMA`{6K(DT%1aFDHn=T8ZP}E9+>vR=C)90lCl2gy$4?yCACyqLAa}=SZU&I2rcOfI
z)Jb+Wq)nX!$|$zm1i4$jn*g7i7>T(F-9T(s5pxr|fl`8vCo8q_scZf-1G?bZ0i8i@
z2C-)cbOvJto6lXlXZz=k>|+h;mVl21r39JBzSnks9sK8ytN)Dj*B7FDWCUJc_!0o1
zTX+|gl~>@MKdpye@8k0BlhS^(Lx5jSUyATme}r#zGy;|`HBZM;QD`hJ#nolY5u_76
z;ybPozFD*g32WCPFeV1E@4W{A@axe7bwx!eSiBhR1woZhDa{5jRzA%3L<4|cQQZtz
zu3YiA?0ce#&est34IGy|3Mok=ZSoW?-|zb}2Ya&*K@fEiMNw-a#qN06kO6pPP#lyT
zBsc#Qj-4ogUhe~)Ua##M$YBPbF*Oy_r#uOz6PUGgH@0lw1)dkc^Sm~`Lx9X1)*UY=
zMz!#5?EfgY7@5b50KEaw88q_k`{&s~;dpvLR~vpy`!*Mp;qUon;PnP@dS9>j3r6+D
z+>w23`lrSIjX7tr;m{c{oev=TXuJls=Zm6<|9t;1czkR!9v?df0Pxw~1K68=7&^TV
zDD`Z~?HJ(x98jK~jt;4l5jr{5oL$P=j$3<nBS;jT>Z|)Fb>MTzfAv*#pD_bH)6xI{
zC7U*(eA_m(69i~k(*OH{S>wFb0AS^kSM8E#|B?QhW=$c$?G65X|3R2cCX7!>veWl}
znS<=ZN1>BPV6DjsM+ZBan}@rNjTk;`sGXjhcM5r@&%xK%Pw{uI^8@yFY|h#NNovMZ
zQ&a8q?K}4%Yv*SWc){)R$jN>Ohxzcx1(2o&%o*O>PX9Q!2pdma27ChK$kFC#jx+4v
zzbOW3Y{1irz3lWYCrh#UOci+FcB(V8JO27F3qbESVovfvd;1Tc#fGC70KK2=`I5!}
zckV|))IlN?rsihrAR>r5c$3gl3Rr&td~-9H$ppyz{x0eYs)=@IKl1~?nM|NEpEH@@
z=c2CC_RhLb?2>2ci)JTj)c|1Bgr@=m0|U*;GovxU6HQbLK#t?E|H~W%wQq+<5(e7^
zxFCv}1J61`NcJa{<3;4=pMk%>KjQm6Y%_bGfljY?s;?zM<Y@o49edEB!$TN7a=2CB
zwqp-?o`;sKySx4YufvAiQiS>&@OXU7Ouiwv)I4i@*gsB}FoGVRo~lF#e;<tL6K<71
zJyi)#ZvZ2n^^a3f@j9$OQizW2{V;KGOiSP&DFj44;9(Fd`NN{QFCZek3(CsM0RUr0
z4M%LxXsp}#KldfTJEy0^r+atQ7n>7;4^0>kzdpTD{mwi0CBXY<WFR0q8b5#c9RMIA
zH5DD=;&9>Zw>A2tbMj291^|J9fqva0y43;zu9%Z&S~XtD0US$@9#QDqI~Mt;&VUdC
zLI^mXSFEeW0US$2co+2Q9*M$>#h`?O5(+^O6zgi4!5vHQm|hq>ARb4Lf74>Wi@I87
zK*ti_ts@@o*%|u_D?lg(p%jc473-?oPn=4huE7`@6^fkiuYwQ;LKq<G6zh6re`F^-
z8XJy%-~IrJ5J-f8alBXdJNm<d7iXbM=TKZKufUphnOL(f6PL;>(4})I7Q8siWB+NE
zB)by&=9|!khoiov1jQ>?qIl&>)R&Y%7aoq#H{W!suQ~xyYFGNMSOLF?2;3?z#)&0M
zaAL_4+$t`HUql4@u2|tz-_>0w+v14^00x7>6cQZL6cQZLWH1;^o@lB|^zKm+cz)(I
ze6lGE#U*99@zYI=du%kky<g~f4c;}Z6DFpN!mhmsP;uoNYHrnH#BYW=)zdtKILyco
z$MnSF-_OU|4>EE7!bM!Wb{$hEKj~CY`wV68B=KDz!n;qzW9hCF$gikDWsMQDNAv|H
z(tY9g=^Th9$+1|y|1{2At;LVEw~>|@dk=j3ejO0e5v!;F7E8D0Ag}BiDsR@|g`~kA
zugqNe&zcW1!6*gC^U&$cd6c#5KXTHvuK?}aUAS^3B*q|e90KKp*Y^sVxBZiwo^E9Y
z$a$JP1x;mD>6ARvssTVubd;g0s><K8?}=s!aHe#EEW!P^%~>cZD+ezKIB@8Q*3p(J
z?b|LvyM}eb6Dgyy>+@_>UAqBM)Zy#=(_oak&9=Ma+b+3dV|wDXMf33I^_eKVSOkva
z@qfGj0m7)3rMV0HC7a;xfOnr5fMq+sMqX7NAn5SX@gfjHv;?5C{Wb$z@6LhvLvnAd
z-gg@3s_y_gA8aYO3`&`n*;<t!9}$Z8o*Is~w;n=X`AxI^IcGsB^_uVK7lI&K*Tt6a
zlr*h;$645~<-}XRQ_{5Z9cN*K`8v<;J0;B>f7#+WPRTQ^8UU<Xy4WsxmhtxMnl;hp
zT9t4d$1Ka#prAlJKVusHwkZpxm&(o8tCWK0cw`?sVm?Vq_XaqQaU4e!bi#2QBeLVS
zZx?_kQhtYBpYKQ2kJaD>0fb24c^=2}PC=*BdBwNfCJPSkfY%nz#b4HM#D(vQz;T>8
zs5xNg?tg%DG4iVN<q^J9dtdz5lY_8)=hw)ussnftAOwsT@z>lUFc(>8t^AMx1OAZQ
z2W$2f;N0~)fMDiB&|zyq88{bNdCm3*`s3Z{!?AqJL342Pg4upfz{iKrfQfqV`1kln
z5jDOfNv+DK_xMK|SNwZqp7d4|<&lP5yI$R7e(Vj55X$|0>lWT$_aSQQZiDA}P@DV9
zoWpU;Xw5T@<Jh(9)lD!zDrXtRtbFsOFXd|MjQH<OS-8{C2wo8EMsmU7*qRUG)%iTn
zGeQVgQ}Z*Hu3UwmZvNa7+$}w!ID-p<pvo6OnM4^^U3(iZ{q+E<?lhZ&+h)dN4#(Ec
z<~a>~#w5zPo5nkMW6M{#(a6lfZQCD$UNK*wiO(@6QOZ@<8u8-#ov6CqWDag-W4~a3
z+`?Dye~bTk<H%b4hX4%3%m2G;IKRw12ztfmT=O5;##;g$fQjch`e@=1Bcl{x47IgJ
zm&qul@@V1^BhPabEziO-M}B;t7%Try!!PFG)5wqS6Qjx>J7%=e@^skEpK8qiHqiJq
z+1N3oRrzW0U5%7dPzF@iH-m!L{IpS8d{<TegoisCDWjkOt~WAJc`(&dCOq6x-TtA`
zMoO94eq)ntKhspwhDNLME&k(8(c(XTDJe!vBGc32my)8&4;eq+NEw4SC1m_~CH@25
zEHk(SplSP#-OHy>NzF)|IPMl9M35ie;MA5RJkL=<5Qt9HN!xeqUJjs1W?C9(<xiWE
znlb9P39ZI|dG@S~+0V^vHU9D`sToU>Vq1;BXi93vyu^rB<FA;Knvp(!P^<A<-GAo1
zoDnp8cI)xyFUaUNXU_fRKd_DCeA@8<^m6VX06<{JkdPpWNPdhlAI6xd(m;vhxVxet
z{&KUXrVfA+z#X}fCb?Q0zm5N^<g>f=^g#zWC*S|q%f(l2tX`hsRsS0xk5(qRQH}Dx
z?JH~A_-*`OCI3Occv11Ci#83jG>%ib6+mnns`^s9Hhvrb*TR3`0p9l7<Tn1j@Y`OS
etj>Rs+dl!+gL0AI@-6HD0000<MNUMnLSTYF%@Pp+
--- a/browser/themes/gnomestripe/newtab/newTab.css
+++ b/browser/themes/gnomestripe/newtab/newTab.css
@@ -1,148 +1,131 @@
-#scrollbox {
-  padding-bottom: 18px;
-  background-color: #fff;
-}
-
-#body {
-  padding-top: 106px;
-  font-family: sans-serif;
-}
-
-.button {
-  padding: 0;
-  border: 0 none;
+:root {
+  -moz-appearance: none;
+  background-color: transparent;
 }
 
-/* TOOLBAR */
-#toolbar {
-  top: 8px;
-  right: 8px;
-  width: 13px;
-  height: 30px;
-  padding: 0;
-  margin: 0;
-}
-
-.toolbar-button {
-  background: transparent url(chrome://browser/skin/newtab/toolbar.png);
-}
-
-#toolbar-button-show {
-  width: 11px;
-  height: 11px;
-  background-position: -10px 0;
-}
-
-#toolbar-button-show:hover {
-  background-position: -10px -12px;
+/* SCROLLBOX */
+#newtab-scrollbox:not([page-disabled]) {
+  background-color: rgb(229,229,229);
+  background-image: url(chrome://browser/skin/newtab/noise.png),
+                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+  background-attachment: fixed;
 }
 
-#toolbar-button-show:active {
-  background-position: -10px -24px;
-}
-
-#toolbar-button-hide {
-  width: 10px;
-  height: 10px;
-}
-
-#toolbar-button-hide:hover {
-  background-position: 0 -12px;
-}
-
-#toolbar-button-hide:active {
-  background-position: 0 -24px;
+/* TOGGLE */
+#newtab-toggle {
+  width: 16px;
+  height: 16px;
+  padding: 0;
+  border: none;
+  background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-#toolbar-button-reset {
-  top: 17px;
-  width: 11px;
-  height: 12px;
-}
-
-#toolbar-button-reset {
-  background-position: -21px 0;
+#newtab-toggle[page-disabled] {
+  background-position: -232px 0;
 }
 
-#toolbar-button-reset:hover {
-  background-position: -21px -12px;
+/* ROWS */
+.newtab-row {
+  margin-bottom: 20px;
 }
 
-#toolbar-button-reset:active {
-  background-position: -21px -24px;
-}
-
-/* GRID */
-#grid {
-  padding: 1px;
-  margin: 0 auto;
+.newtab-row:last-child {
+  margin-bottom: 0;
 }
 
 /* CELLS */
-.cell {
-  outline: 1px dashed #ccc;
-  outline-offset: -1px;
+.newtab-cell {
+  -moz-margin-end: 20px;
+  background-color: rgba(255,255,255,.2);
+  border: 1px solid;
+  border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
+  border-radius: 1px;
+  -moz-transition: border-color 100ms ease-out;
+}
+
+.newtab-cell:empty {
+  border: 1px dashed;
+  border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
+}
+
+.newtab-cell:last-child {
+  -moz-margin-end: 0;
+}
+
+.newtab-cell:hover:not(:empty) {
+  border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
-.site {
-  background-color: #ececec;
-  -moz-transition: 200ms ease-out;
-  -moz-transition-property: top, left, box-shadow, opacity;
+.newtab-site {
+  text-decoration: none;
+  -moz-transition-property: top, left, opacity, box-shadow, background-color;
 }
 
-.site[dragged] {
-  -moz-transition-property: box-shadow;
+.newtab-site:hover,
+.newtab-site[dragged] {
+  box-shadow: 0 0 10px rgba(8,22,37,.3);
+}
+
+.newtab-site[dragged] {
+  -moz-transition-property: box-shadow, background-color;
+  background-color: rgb(242,242,242);
 }
 
-.site[ontop] {
-  box-shadow: 0 1px 4px #000;
-  outline: none;
+/* THUMBNAILS */
+.newtab-thumbnail {
+  background-origin: padding-box;
+  background-clip: padding-box;
+  background-repeat: no-repeat;
+  background-size: cover;
 }
 
-/* SITE TITLE */
-.site-title {
-  height: 2.4em;
-  width: 189px;
-  padding: 0 6px;
-  background-color: rgba(0,0,0,0.5);
-  border: solid transparent;
-  border-width: 6px 0;
-  color: #fff;
-  text-decoration: none;
-  line-height: 1.2em;
-  font-weight: 700;
+/* TITLES */
+.newtab-title {
+  padding: 0 8px;
+  background-color: rgba(248,249,251,.95);
+  color: #1f364c;
+  font-size: 12px;
+  line-height: 24px;
 }
 
-/* SITE STRIP */
-.site-strip {
-  padding: 4px 3px;
-  background-color: rgba(0,0,0,0.5);
+/* CONTROLS */
+.newtab-control {
+  width: 24px;
+  height: 24px;
+  padding: 1px 2px 3px;
+  border: none;
+  background: transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-.strip-button {
-  width: 17px;
-  height: 17px;
-  background: transparent url(chrome://browser/skin/newtab/strip.png);
+.newtab-control-pin:hover {
+  background-position: -24px 0;
 }
 
-.strip-button-pin:hover {
-  background-position: 0 -17px;
+.newtab-control-pin:active {
+  background-position: -48px 0;
 }
 
-.strip-button-pin:active,
-.site[pinned] .strip-button-pin {
-  background-position: 0 -34px;
+.newtab-control-pin[pinned] {
+  background-position: -72px 0;
+}
+
+.newtab-control-pin[pinned]:hover {
+  background-position: -96px 0;
+}
+
+.newtab-control-pin[pinned]:active {
+  background-position: -120px 0;
 }
 
-.strip-button-block {
-  background-position: -17px 0;
+.newtab-control-block {
+  background-position: -144px 0;
 }
 
-.strip-button-block:hover {
-  background-position: -17px -17px;
+.newtab-control-block:hover {
+  background-position: -168px 0;
 }
 
-.strip-button-block:active {
-  background-position: -17px -34px;
+.newtab-control-block:active {
+  background-position: -192px 0;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01d340aaa9095a54d19071516cf9e0ca75b1f72e
GIT binary patch
literal 2118
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
deleted file mode 100644
index 2527df6e72b5c80b91e180af9644ba96a5c148d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 389f689aa2a7611f53977594c048f79c4991affd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -49,18 +49,18 @@ browser.jar:
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/newtab/newTab.css                    (newtab/newTab.css)
-  skin/classic/browser/newtab/strip.png                     (newtab/strip.png)
-  skin/classic/browser/newtab/toolbar.png                   (newtab/toolbar.png)
+  skin/classic/browser/newtab/controls.png                  (newtab/controls.png)
+  skin/classic/browser/newtab/noise.png                     (newtab/noise.png)
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/places/allBookmarks.png              (places/allBookmarks.png)
 * skin/classic/browser/places/places.css                    (places/places.css)
 * skin/classic/browser/places/organizer.css                 (places/organizer.css)
   skin/classic/browser/places/query.png                     (places/query.png)
   skin/classic/browser/places/bookmarksMenu.png             (places/bookmarksMenu.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14f382fbdd18a1209f3dcd63831014b5ad2fc428
GIT binary patch
literal 4180
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
--- a/browser/themes/pinstripe/newtab/newTab.css
+++ b/browser/themes/pinstripe/newtab/newTab.css
@@ -1,147 +1,131 @@
-#scrollbox {
-  padding-bottom: 18px;
-  background-color: #fff;
-}
-
-#body {
-  padding-top: 106px;
-  font-family: sans-serif;
-}
-
-.button {
-  padding: 0;
-  border: 0 none;
+:root {
+  -moz-appearance: none;
+  background-color: transparent;
 }
 
-/* TOOLBAR */
-#toolbar {
-  top: 8px;
-  right: 8px;
-  width: 13px;
-  height: 30px;
-  padding: 0;
-  margin: 0;
-}
-
-.toolbar-button {
-  background: transparent url(chrome://browser/skin/newtab/toolbar.png);
-}
-
-#toolbar-button-show {
-  width: 11px;
-  height: 11px;
-  background-position: -10px 0;
-}
-
-#toolbar-button-show:hover {
-  background-position: -10px -12px;
+/* SCROLLBOX */
+#newtab-scrollbox:not([page-disabled]) {
+  background-color: rgb(229,229,229);
+  background-image: url(chrome://browser/skin/newtab/noise.png),
+                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+  background-attachment: fixed;
 }
 
-#toolbar-button-show:active {
-  background-position: -10px -24px;
-}
-
-#toolbar-button-hide {
-  width: 10px;
-  height: 10px;
-}
-
-#toolbar-button-hide:hover {
-  background-position: 0 -12px;
-}
-
-#toolbar-button-hide:active {
-  background-position: 0 -24px;
+/* TOGGLE */
+#newtab-toggle {
+  width: 16px;
+  height: 16px;
+  padding: 0;
+  border: none;
+  background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-#toolbar-button-reset {
-  top: 17px;
-  width: 11px;
-  height: 12px;
-}
-
-#toolbar-button-reset {
-  background-position: -21px 0;
+#newtab-toggle[page-disabled] {
+  background-position: -232px 0;
 }
 
-#toolbar-button-reset:hover {
-  background-position: -21px -12px;
+/* ROWS */
+.newtab-row {
+  margin-bottom: 20px;
 }
 
-#toolbar-button-reset:active {
-  background-position: -21px -24px;
-}
-
-/* GRID */
-#grid {
-  padding: 1px;
-  margin: 0 auto;
+.newtab-row:last-child {
+  margin-bottom: 0;
 }
 
 /* CELLS */
-.cell {
-  outline: 1px dashed #ccc;
-  outline-offset: -1px;
+.newtab-cell {
+  -moz-margin-end: 20px;
+  background-color: rgba(255,255,255,.2);
+  border: 1px solid;
+  border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
+  border-radius: 1px;
+  -moz-transition: border-color 100ms ease-out;
+}
+
+.newtab-cell:empty {
+  border: 1px dashed;
+  border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
+}
+
+.newtab-cell:last-child {
+  -moz-margin-end: 0;
+}
+
+.newtab-cell:hover:not(:empty) {
+  border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
-.site {
-  background-color: #ececec;
-  -moz-transition: 200ms ease-out;
-  -moz-transition-property: top, left, box-shadow, opacity;
+.newtab-site {
+  text-decoration: none;
+  -moz-transition-property: top, left, opacity, box-shadow, background-color;
 }
 
-.site[dragged] {
-  -moz-transition-property: box-shadow;
+.newtab-site:hover,
+.newtab-site[dragged] {
+  box-shadow: 0 0 10px rgba(8,22,37,.3);
+}
+
+.newtab-site[dragged] {
+  -moz-transition-property: box-shadow, background-color;
+  background-color: rgb(242,242,242);
 }
 
-.site[ontop] {
-  box-shadow: 0 1px 4px #000;
+/* THUMBNAILS */
+.newtab-thumbnail {
+  background-origin: padding-box;
+  background-clip: padding-box;
+  background-repeat: no-repeat;
+  background-size: cover;
 }
 
-/* SITE TITLE */
-.site-title {
-  height: 2.4em;
-  width: 189px;
-  padding: 0 6px;
-  background-color: rgba(0,0,0,0.5);
-  border: solid transparent;
-  border-width: 6px 0;
-  color: #fff;
-  text-decoration: none;
-  line-height: 1.2em;
-  font-weight: 700;
+/* TITLES */
+.newtab-title {
+  padding: 0 8px;
+  background-color: rgba(248,249,251,.95);
+  color: #1f364c;
+  font-size: 12px;
+  line-height: 24px;
 }
 
-/* SITE STRIP */
-.site-strip {
-  padding: 4px 3px;
-  background-color: rgba(0,0,0,0.5);
+/* CONTROLS */
+.newtab-control {
+  width: 24px;
+  height: 24px;
+  padding: 1px 2px 3px;
+  border: none;
+  background: transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-.strip-button {
-  width: 17px;
-  height: 17px;
-  background: transparent url(chrome://browser/skin/newtab/strip.png);
+.newtab-control-pin:hover {
+  background-position: -24px 0;
 }
 
-.strip-button-pin:hover {
-  background-position: 0 -17px;
+.newtab-control-pin:active {
+  background-position: -48px 0;
 }
 
-.strip-button-pin:active,
-.site[pinned] .strip-button-pin {
-  background-position: 0 -34px;
+.newtab-control-pin[pinned] {
+  background-position: -72px 0;
+}
+
+.newtab-control-pin[pinned]:hover {
+  background-position: -96px 0;
+}
+
+.newtab-control-pin[pinned]:active {
+  background-position: -120px 0;
 }
 
-.strip-button-block {
-  background-position: -17px 0;
+.newtab-control-block {
+  background-position: -144px 0;
 }
 
-.strip-button-block:hover {
-  background-position: -17px -17px;
+.newtab-control-block:hover {
+  background-position: -168px 0;
 }
 
-.strip-button-block:active {
-  background-position: -17px -34px;
+.newtab-control-block:active {
+  background-position: -192px 0;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01d340aaa9095a54d19071516cf9e0ca75b1f72e
GIT binary patch
literal 2118
zc$@)72)Xx(P)<h;3K|Lk000e1NJLTq001xm001xu1ONa4{R=S+00002VoOIv0RM-N
z%)bBt010qNS#tmY3ljhU3ljkVnw%H_000Sga6xAP001xm001xm&hCs?000MbNkl<Z
zSi@D=+jZMW5(eOpwjTOXjzG-}lmVL&j2!_R5zK4^AR@3G0e}d09Ra`yb{qk~46F#S
z4=8cG(mA|<V53p>--?HvdIhUa_M+;X6tf#nR@I;yaMwDUa5OpE3_1&rij$kwgjpBQ
zt3#iPRi|LEXk0XkRWCbQbWSK%v(W`v*6DR-WWA&6B3sSwR;^XR%$E8zr7dl#rkb`?
z(w44iNhS4ZOV>EEr7d0Kvn_2Yr<%4jrIM~`OH;~8%ITV>w56I#x~3BAeymTUXV1R-
z!%xrdKFhMvCpTADS?Ag8)!nmdHu|bDdh>@LI)AyTep!v46?eb<fghfI{Q30kt}3!$
zp8at5>Whn?zRF&$Uh!<yTOA$z!hbxw`r@lMRq?}DZ@wD+<+Ja;`GTvbN#le;MR9YI
zO**R?18y#|-r1xE6u6;{-re+Q9c9g<D+4U4PfOa;l9sfknyzU|HBD(tqVhGK_s1#K
zw4^2V>6)%-OV^a6H#IG(PdQCV+LE-SoJ#tTRoU55hu%pEm=+whIGYVRtX5g4(P`uT
zqG+6~R@GwEn{65ehb^(n8eA06Xk|2dM@4pWbHW-RJ*s+xn+w6CStj0fPDU5m2SKtO
z(fi-NOM0DNA1o*uqoQC#qdFPgbUK~t7H6H!kFD4%x%Z)@Eluf~N?MY%1pfOpC25M!
z-n+F0=5y*(iPu}Kl2eISH9ZX$XMM1DRx}oaMW;7o)Y>#wcPBJavRTz*&>BM=#NDo7
z!l9&Mun-E9&2FJSy#|ZH9kU5%Yp73Fv<^1MkQllEuE+7imUeXX&a&0ytk+?V%MKbv
zj@@QCwlanq^*ULraj_a@v&D>?)(2XvjEj?OHtC$4RD&~aHuN}Z6tm72`&>;%*$Y~Y
zEL&xR&dn7EX)~zi*xUX$Ta7M?#-xi)9Arh0hPdc#Rh;FhIcJmegUwHyH4wl103BXr
zlR3!J>Z~rR)yeGqUSFFo=(RfPyaW$Q^sHfr;_{m;>~gTfFsDAixeJCkH>Z+H+ESl#
zx~3B6_m8#uw4^DOw56v5u3BeYtU8ydBxhN6)9N0~-s#xuqI7pm0ZR`MXS2J>(P2wx
z1()BvXg_^48Bjx)_QwXjSusbO$wpc0?4pKH>|iK9G_s3X=N>zwy31y>YQ$)Wx}L4k
z)<LlvQPFFW-JEq^6kTld<A0yNc=M-cZ(e+t@x?FMCqMAX%`bPKK~)@l)_K$U=DTmP
zwMO>CzwzvD^tT_r8mSLmDZi=D?#tKIrzKreP5q<kesk(~HCjTkrZmMjrda2i>=v<w
z?eCpm0yFQ6msHa=NlU5^d)iH@56dr)t-XI|-{6*>ZWf(RF~~}=BFE!way01-u7Rx*
zLR@sgkj2qaZzNPJ8v-teEj4;gIPD&*{_(C=(LNx!Gk*VkGAKHI$lvZEr;w1@&Bcn3
z_op>1`(NJl2H*W5d(->n&7XexTh{4(b9PYi(@oX*kL;T_XWtyX;$JGV;)|>7u%#W-
zqdpQuAAaj`AK5t^SbUk)8O6ou6s}Q%u49m~vF^!En$i-UwKqCPn@hCnT`p?c{tp!I
z_^a{UN2^Pcwp7!S4t?6G@^0}<WQoRRFe+NdsO+wv;;hb#(Qa3V@afLQIV@^7s1Mbs
zasJKn8?72SqiD@~vr}N`Jx_Brnw%7?YBD>9=&wdET8*<qN$q3d5<WJBFIBBsaki>f
zS!)mH@5b20k=sMBc6`+b?(CAgrSg#5fBs7lZ)fQi+<xc!_TcmqBL5Hnuc;>Knzr=u
z_VmpU#ZP~E)wzXYzH0obxXZFHK3OsPr19AeqsFsWZ@wsQp8f6BD?Tee8~xkS)9k3q
zPBEq26*twO)fipOA=#6&_CdVHWYrt2CMEPWM}%9AQKmyp`C<FbgA22Y7gU3y2{VV2
zESv2k)eyZ{q6-|9=tIM9IBjVC6ltaprJt~BOfgEWPDayjw$oUgT>_NHpy5kgx>`LQ
z19Y9)*%gaDt(7qKDR{6NT(ml;Fw`jwKD#SnN`0__>bx_#M&_T=5_8xRv)46{@NW4z
z@YDas+AWw|l9(uJ%E5lAq$d$rb}f8)7&o-`LH1pZilg43bC0pNI9g2BDBaHXvjMHe
z>M*6z$=#rOQO#~vr-#+=^0mJk9?QI6uIL}r#B3zUxJH<6eJHZ5RkgCC8+y0k^)42b
zSiX(rXC;JtjSRle%h`*;If8LEI`pZA%<ba_`7zWTwQi3PyiYKl)v7nj4}00=Z*`O{
z;e=%u3Qu=Oy*;E)j#2$7P%_8OuK~O+aI>pXW7VjS7*nI4_vqbX_B6zpx5xATw-!$Z
z*<F>bT2wWRW;d6j%F&mDEr7BA%CX<u%^{~L798S-kP&-~%rR~5YJZNfxNCk6DZhCM
zA-_N7&e5ukw0`K*j*xf4c~o_8(_W-=<c)p0+2#A>X0RCCypJop^|xU-7nz+td%Bsz
z?xqKYu8)+ogm}Ln*;93nke1Vyq-*L^j!d+L1^*ArT{R<!oMR>c001R)MObuXVRU6W
zV{&C-bY%cCFflSMFf%PNGE^}$IxsalF*qwQF*-0Xc5IQR0000bbVXQnWMOn=I&E)c
wX=Zr<GB7bREif}JF)~y!GdeIdIyE&bFflqXFb!@k9smFU07*qoM6N<$g5J3onE(I)
deleted file mode 100644
index 2527df6e72b5c80b91e180af9644ba96a5c148d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 75d6f13d8c6e6a1cfc0d5766cfec91378e0b60c0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -54,18 +54,18 @@ browser.jar:
         skin/classic/browser/feeds/feedIcon16.png                    (feeds/feedIcon16.png)
         skin/classic/browser/feeds/audioFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/audioFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/videoFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/videoFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/subscribe.css                     (feeds/subscribe.css)
         skin/classic/browser/feeds/subscribe-ui.css                  (feeds/subscribe-ui.css)
         skin/classic/browser/newtab/newTab.css                       (newtab/newTab.css)
-        skin/classic/browser/newtab/strip.png                        (newtab/strip.png)
-        skin/classic/browser/newtab/toolbar.png                      (newtab/toolbar.png)
+        skin/classic/browser/newtab/controls.png                     (newtab/controls.png)
+        skin/classic/browser/newtab/noise.png                        (newtab/noise.png)
         skin/classic/browser/places/places.css                       (places/places.css)
 *       skin/classic/browser/places/organizer.css                    (places/organizer.css)
         skin/classic/browser/places/bookmark.png                     (places/bookmark.png)
         skin/classic/browser/places/editBookmark.png                 (places/editBookmark.png)
         skin/classic/browser/places/query.png                        (places/query.png)
         skin/classic/browser/places/bookmarksMenu.png                (places/bookmarksMenu.png)
         skin/classic/browser/places/bookmarksToolbar.png             (places/bookmarksToolbar.png)
         skin/classic/browser/places/calendar.png                     (places/calendar.png)
@@ -226,18 +226,18 @@ browser.jar:
         skin/classic/aero/browser/feeds/feedIcon16.png               (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/aero/browser/feeds/subscribe-ui.css             (feeds/subscribe-ui.css)
         skin/classic/aero/browser/newtab/newTab.css                  (newtab/newTab.css)
-        skin/classic/aero/browser/newtab/strip.png                   (newtab/strip.png)
-        skin/classic/aero/browser/newtab/toolbar.png                 (newtab/toolbar.png)
+        skin/classic/aero/browser/newtab/controls.png                (newtab/controls.png)
+        skin/classic/aero/browser/newtab/noise.png                   (newtab/noise.png)
 *       skin/classic/aero/browser/places/places.css                  (places/places-aero.css)
 *       skin/classic/aero/browser/places/organizer.css               (places/organizer-aero.css)
         skin/classic/aero/browser/places/bookmark.png                (places/bookmark.png)
         skin/classic/aero/browser/places/editBookmark.png            (places/editBookmark.png)
         skin/classic/aero/browser/places/query.png                   (places/query-aero.png)
         skin/classic/aero/browser/places/bookmarksMenu.png           (places/bookmarksMenu-aero.png)
         skin/classic/aero/browser/places/bookmarksToolbar.png        (places/bookmarksToolbar-aero.png)
         skin/classic/aero/browser/places/calendar.png                (places/calendar-aero.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14f382fbdd18a1209f3dcd63831014b5ad2fc428
GIT binary patch
literal 4180
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
--- a/browser/themes/winstripe/newtab/newTab.css
+++ b/browser/themes/winstripe/newtab/newTab.css
@@ -1,148 +1,131 @@
-#scrollbox {
-  padding-bottom: 18px;
-  background-color: #fff;
-}
-
-#body {
-  padding-top: 106px;
-  font-family: sans-serif;
-}
-
-.button {
-  padding: 0;
-  border: 0 none;
+:root {
+  -moz-appearance: none;
+  background-color: transparent;
 }
 
-/* TOOLBAR */
-#toolbar {
-  top: 8px;
-  right: 8px;
-  width: 13px;
-  height: 30px;
-  padding: 0;
-  margin: 0;
-}
-
-.toolbar-button {
-  background: transparent url(chrome://browser/skin/newtab/toolbar.png);
-}
-
-#toolbar-button-show {
-  width: 11px;
-  height: 11px;
-  background-position: -10px 0;
-}
-
-#toolbar-button-show:hover {
-  background-position: -10px -12px;
+/* SCROLLBOX */
+#newtab-scrollbox:not([page-disabled]) {
+  background-color: rgb(229,229,229);
+  background-image: url(chrome://browser/skin/newtab/noise.png),
+                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+  background-attachment: fixed;
 }
 
-#toolbar-button-show:active {
-  background-position: -10px -24px;
-}
-
-#toolbar-button-hide {
-  width: 10px;
-  height: 10px;
-}
-
-#toolbar-button-hide:hover {
-  background-position: 0 -12px;
-}
-
-#toolbar-button-hide:active {
-  background-position: 0 -24px;
+/* TOGGLE */
+#newtab-toggle {
+  width: 16px;
+  height: 16px;
+  padding: 0;
+  border: none;
+  background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-#toolbar-button-reset {
-  top: 17px;
-  width: 11px;
-  height: 12px;
-}
-
-#toolbar-button-reset {
-  background-position: -21px 0;
+#newtab-toggle[page-disabled] {
+  background-position: -232px 0;
 }
 
-#toolbar-button-reset:hover {
-  background-position: -21px -12px;
+/* ROWS */
+.newtab-row {
+  margin-bottom: 20px;
 }
 
-#toolbar-button-reset:active {
-  background-position: -21px -24px;
-}
-
-/* GRID */
-#grid {
-  padding: 1px;
-  margin: 0 auto;
+.newtab-row:last-child {
+  margin-bottom: 0;
 }
 
 /* CELLS */
-.cell {
-  outline: 1px dashed #ccc;
-  outline-offset: -1px;
+.newtab-cell {
+  -moz-margin-end: 20px;
+  background-color: rgba(255,255,255,.2);
+  border: 1px solid;
+  border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
+  border-radius: 1px;
+  -moz-transition: border-color 100ms ease-out;
+}
+
+.newtab-cell:empty {
+  border: 1px dashed;
+  border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
+}
+
+.newtab-cell:last-child {
+  -moz-margin-end: 0;
+}
+
+.newtab-cell:hover:not(:empty) {
+  border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
-.site {
-  background-color: #ececec;
-  -moz-transition: 200ms ease-out;
-  -moz-transition-property: top, left, box-shadow, opacity;
+.newtab-site {
+  text-decoration: none;
+  -moz-transition-property: top, left, opacity, box-shadow, background-color;
 }
 
-.site[dragged] {
-  -moz-transition-property: box-shadow;
+.newtab-site:hover,
+.newtab-site[dragged] {
+  box-shadow: 0 0 10px rgba(8,22,37,.3);
+}
+
+.newtab-site[dragged] {
+  -moz-transition-property: box-shadow, background-color;
+  background-color: rgb(242,242,242);
 }
 
-.site[ontop] {
-  box-shadow: 0 1px 4px #000;
-  outline: none;
+/* THUMBNAILS */
+.newtab-thumbnail {
+  background-origin: padding-box;
+  background-clip: padding-box;
+  background-repeat: no-repeat;
+  background-size: cover;
 }
 
-/* SITE TITLE */
-.site-title {
-  height: 2.4em;
-  width: 189px;
-  padding: 0 6px;
-  background-color: rgba(0,0,0,0.5);
-  border: solid transparent;
-  border-width: 6px 0;
-  color: #fff;
-  text-decoration: none;
-  line-height: 1.2em;
-  font-weight: 700;
+/* TITLES */
+.newtab-title {
+  padding: 0 8px;
+  background-color: rgba(248,249,251,.95);
+  color: #1f364c;
+  font-size: 12px;
+  line-height: 24px;
 }
 
-/* SITE STRIP */
-.site-strip {
-  padding: 4px 3px;
-  background-color: rgba(0,0,0,0.5);
+/* CONTROLS */
+.newtab-control {
+  width: 24px;
+  height: 24px;
+  padding: 1px 2px 3px;
+  border: none;
+  background: transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-.strip-button {
-  width: 17px;
-  height: 17px;
-  background: transparent url(chrome://browser/skin/newtab/strip.png);
+.newtab-control-pin:hover {
+  background-position: -24px 0;
 }
 
-.strip-button-pin:hover {
-  background-position: 0 -17px;
+.newtab-control-pin:active {
+  background-position: -48px 0;
 }
 
-.strip-button-pin:active,
-.site[pinned] .strip-button-pin {
-  background-position: 0 -34px;
+.newtab-control-pin[pinned] {
+  background-position: -72px 0;
+}
+
+.newtab-control-pin[pinned]:hover {
+  background-position: -96px 0;
+}
+
+.newtab-control-pin[pinned]:active {
+  background-position: -120px 0;
 }
 
-.strip-button-block {
-  background-position: -17px 0;
+.newtab-control-block {
+  background-position: -144px 0;
 }
 
-.strip-button-block:hover {
-  background-position: -17px -17px;
+.newtab-control-block:hover {
+  background-position: -168px 0;
 }
 
-.strip-button-block:active {
-  background-position: -17px -34px;
+.newtab-control-block:active {
+  background-position: -192px 0;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01d340aaa9095a54d19071516cf9e0ca75b1f72e
GIT binary patch
literal 2118
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
deleted file mode 100644
index 2527df6e72b5c80b91e180af9644ba96a5c148d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 33bb4a320e76cc7a346ca4beb60e89a85a48aa2c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -454,17 +454,17 @@ def wrapCommand(cmd):
   return cmd
 
 class ShutdownLeakLogger(object):
   """
   Parses the mochitest run log when running a debug build, assigns all leaked
   DOM windows (that are still around after test suite shutdown, despite running
   the GC) to the tests that created them and prints leak statistics.
   """
-  MAX_LEAK_COUNT = 120
+  MAX_LEAK_COUNT = 121
 
   def __init__(self, logger):
     self.logger = logger
     self.tests = []
     self.leakedWindows = {}
     self.leakedDocShells = set()
     self.currentTest = None
     self.seenShutdown = False
@@ -486,17 +486,17 @@ class ShutdownLeakLogger(object):
       self.seenShutdown = True
 
   def parse(self):
     leakingTests = self._parseLeakingTests()
 
     if leakingTests:
       totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
       totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
-      msgType = "INFO" if totalWindows + totalDocShells < self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
+      msgType = "INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
       self.logger.info("TEST-%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
 
     for test in leakingTests:
       self.logger.info("\n[%s]", test["fileName"])
 
       for url, count in self._zipLeakedWindows(test["leakedWindows"]):
         self.logger.info("  %d window(s) [url = %s]", count, url)
 
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -105,16 +105,19 @@ public:
   }
 
   virtual ~nsDOMFileBase() {}
 
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(PRUint64 aStart, PRUint64 aLength,
               const nsAString& aContentType) = 0;
 
+  virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
+  GetSubBlobs() const { return nsnull; }
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMBLOB
   NS_DECL_NSIDOMFILE
   NS_DECL_NSIXHRSENDABLE
   NS_DECL_NSIMUTABLE
 
 protected:
   bool IsSizeUnknown()
--- a/content/base/public/nsIDOMFile.idl
+++ b/content/base/public/nsIDOMFile.idl
@@ -98,10 +98,17 @@ interface nsIDOMFile : nsIDOMBlob
   [noscript] readonly attribute DOMString mozFullPathInternal;
 };
 
 [scriptable, builtinclass, uuid(006d2cde-ec18-41d4-acc3-43682dd418e2)]
 interface nsIDOMMozBlobBuilder : nsISupports
 {
   nsIDOMBlob getBlob([optional] in DOMString contentType);
   nsIDOMFile getFile(in DOMString name, [optional] in DOMString contentType);
-  [implicit_jscontext] void append(in jsval data);
+  [implicit_jscontext] void append(in jsval data,
+                                   [optional] in DOMString endings);
 };
+
+dictionary BlobPropertyBag
+{
+  DOMString type;
+  DOMString endings = "transparent";
+};
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -39,19 +39,23 @@
 #include "jstypedarray.h"
 #include "nsAutoPtr.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsStringStream.h"
 #include "nsTArray.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
 
 using namespace mozilla;
 
+NS_IMPL_ISUPPORTS_INHERITED1(nsDOMMultipartFile, nsDOMFileBase,
+                             nsIJSNativeInitializer)
+
 NS_IMETHODIMP
 nsDOMMultipartFile::GetSize(PRUint64* aLength)
 {
   if (mLength == UINT64_MAX) {
     CheckedUint64 length = 0;
   
     PRUint32 i;
     PRUint32 len = mBlobs.Length();
@@ -161,160 +165,276 @@ nsDOMMultipartFile::CreateSlice(PRUint64
     length -= NS_MIN<PRUint64>(l, length);
   }
 
   // we can create our blob now
   nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartFile(blobs, aContentType);
   return blob.forget();
 }
 
-DOMCI_DATA(MozBlobBuilder, nsDOMBlobBuilder)
+/* static */ nsresult
+nsDOMMultipartFile::NewBlob(nsISupports* *aNewObject)
+{
+  nsCOMPtr<nsISupports> file = do_QueryObject(new nsDOMMultipartFile());
+  file.forget(aNewObject);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMMultipartFile::Initialize(nsISupports* aOwner,
+                               JSContext* aCx,
+                               JSObject* aObj,
+                               PRUint32 aArgc,
+                               jsval* aArgv)
+{
+  bool nativeEOL = false;
+  if (aArgc > 1) {
+    mozilla::dom::BlobPropertyBag d;
+    nsresult rv = d.Init(aCx, &aArgv[1]);
+    NS_ENSURE_SUCCESS(rv, rv);
+    mContentType = d.type;
+    if (d.endings.EqualsLiteral("native")) {
+      nativeEOL = true;
+    } else if (!d.endings.EqualsLiteral("transparent")) {
+      return NS_ERROR_DOM_INVALID_STATE_ERR;
+    }
+  }
+
+  if (aArgc > 0) {
+    if (!aArgv[0].isObject()) {
+      return NS_ERROR_INVALID_ARG; // We're not interested
+    }
+
+    JSObject& obj = aArgv[0].toObject();
+
+    if (!JS_IsArrayObject(aCx, &obj)) {
+      return NS_ERROR_INVALID_ARG; // We're not interested
+    }
+
+    BlobSet blobSet;
 
-NS_IMPL_ADDREF(nsDOMBlobBuilder)
-NS_IMPL_RELEASE(nsDOMBlobBuilder)
-NS_INTERFACE_MAP_BEGIN(nsDOMBlobBuilder)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozBlobBuilder)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozBlobBuilder)
-NS_INTERFACE_MAP_END
+    uint32_t length;
+    JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, &obj, &length));
+    for (uint32_t i = 0; i < length; ++i) {
+      jsval element;
+      if (!JS_GetElement(aCx, &obj, i, &element))
+        return NS_ERROR_INVALID_ARG;
+
+      if (element.isObject()) {
+        JSObject& obj = element.toObject();
+        nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(
+          nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, &obj));
+        if (blob) {
+          // Flatten so that multipart blobs will never nest
+          nsDOMFileBase* file = static_cast<nsDOMFileBase*>(
+              static_cast<nsIDOMBlob*>(blob));
+          const nsTArray<nsCOMPtr<nsIDOMBlob> >*
+              subBlobs = file->GetSubBlobs();
+          if (subBlobs) {
+            blobSet.AppendBlobs(*subBlobs);
+          } else {
+            blobSet.AppendBlob(blob);
+          }
+        } else if (js_IsArrayBuffer(&obj)) {
+          JSObject* buffer = js::ArrayBuffer::getArrayBuffer(&obj);
+          if (!buffer)
+            return NS_ERROR_DOM_INVALID_STATE_ERR;
+          blobSet.AppendArrayBuffer(buffer);
+        } else {
+          // neither arraybuffer nor blob
+          return NS_ERROR_DOM_INVALID_STATE_ERR;
+        }
+      } else if (element.isString()) {
+        blobSet.AppendString(element.toString(), nativeEOL, aCx);
+      } else {
+        // neither object nor string
+        return NS_ERROR_DOM_INVALID_STATE_ERR;
+      }
+    }
+
+    mBlobs = blobSet.GetBlobs();
+  }
+
+  return NS_OK;
+}
 
 nsresult
-nsDOMBlobBuilder::AppendVoidPtr(const void* aData, PRUint32 aLength)
+BlobSet::AppendVoidPtr(const void* aData, PRUint32 aLength)
 {
   NS_ENSURE_ARG_POINTER(aData);
 
   PRUint64 offset = mDataLen;
 
   if (!ExpandBufferSize(aLength))
     return NS_ERROR_OUT_OF_MEMORY;
 
   memcpy((char*)mData + offset, aData, aLength);
   return NS_OK;
 }
 
 nsresult
-nsDOMBlobBuilder::AppendString(JSString* aString, JSContext* aCx)
+BlobSet::AppendString(JSString* aString, bool nativeEOL, JSContext* aCx)
 {
   nsDependentJSString xpcomStr;
   if (!xpcomStr.init(aCx, aString)) {
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
-  NS_ConvertUTF16toUTF8 utf8Str(xpcomStr);
+  nsCString utf8Str = NS_ConvertUTF16toUTF8(xpcomStr);
+
+  if (nativeEOL) {
+    if (utf8Str.FindChar('\r') != kNotFound) {
+      utf8Str.ReplaceSubstring("\r\n", "\n");
+      utf8Str.ReplaceSubstring("\r", "\n");
+    }
+#ifdef XP_WIN
+    utf8Str.ReplaceSubstring("\n", "\r\n");
+#endif
+  }
 
   return AppendVoidPtr((void*)utf8Str.Data(),
                        utf8Str.Length());
 }
 
 nsresult
-nsDOMBlobBuilder::AppendBlob(nsIDOMBlob* aBlob)
+BlobSet::AppendBlob(nsIDOMBlob* aBlob)
 {
   NS_ENSURE_ARG_POINTER(aBlob);
 
   Flush();
   mBlobs.AppendElement(aBlob);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMBlobBuilder::AppendArrayBuffer(JSObject* aBuffer)
+BlobSet::AppendBlobs(const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlob)
+{
+  Flush();
+  mBlobs.AppendElements(aBlob);
+
+  return NS_OK;
+}
+
+nsresult
+BlobSet::AppendArrayBuffer(JSObject* aBuffer)
 {
   return AppendVoidPtr(JS_GetArrayBufferData(aBuffer), JS_GetArrayBufferByteLength(aBuffer));
 }
 
+DOMCI_DATA(MozBlobBuilder, nsDOMBlobBuilder)
+
+NS_IMPL_ADDREF(nsDOMBlobBuilder)
+NS_IMPL_RELEASE(nsDOMBlobBuilder)
+NS_INTERFACE_MAP_BEGIN(nsDOMBlobBuilder)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMMozBlobBuilder)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozBlobBuilder)
+NS_INTERFACE_MAP_END
+
 /* nsIDOMBlob getBlob ([optional] in DOMString contentType); */
 NS_IMETHODIMP
 nsDOMBlobBuilder::GetBlob(const nsAString& aContentType,
                           nsIDOMBlob** aBlob)
 {
   return GetBlobInternal(aContentType, true, aBlob);
 }
 
 nsresult
 nsDOMBlobBuilder::GetBlobInternal(const nsAString& aContentType,
                                   bool aClearBuffer,
                                   nsIDOMBlob** aBlob)
 {
   NS_ENSURE_ARG(aBlob);
 
-  Flush();
+  nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = mBlobSet.GetBlobs();
 
-  nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartFile(mBlobs,
+  nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartFile(blobs,
                                                      aContentType);
   blob.forget(aBlob);
 
   // NB: This is a willful violation of the spec.  The spec says that
   // the existing contents of the BlobBuilder should be included
   // in the next blob produced.  This seems silly and has been raised
   // on the WHATWG listserv.
   if (aClearBuffer) {
-    mBlobs.Clear();
+    blobs.Clear();
   }
 
   return NS_OK;
 }
 
 /* nsIDOMBlob getFile (in DOMString name, [optional] in DOMString contentType); */
 NS_IMETHODIMP
 nsDOMBlobBuilder::GetFile(const nsAString& aName,
                           const nsAString& aContentType,
                           nsIDOMFile** aFile)
 {
   NS_ENSURE_ARG(aFile);
 
-  Flush();
+  nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = mBlobSet.GetBlobs();
 
-  nsCOMPtr<nsIDOMFile> file = new nsDOMMultipartFile(mBlobs,
+  nsCOMPtr<nsIDOMFile> file = new nsDOMMultipartFile(blobs,
                                                      aName,
                                                      aContentType);
   file.forget(aFile);
 
   // NB: This is a willful violation of the spec.  The spec says that
   // the existing contents of the BlobBuilder should be included
   // in the next blob produced.  This seems silly and has been raised
   // on the WHATWG listserv.
-  mBlobs.Clear();
+  blobs.Clear();
 
   return NS_OK;
 }
 
-/* [implicit_jscontext] void append (in jsval data); */
+/* [implicit_jscontext] void append (in jsval data,
+                                     [optional] in DOMString endings); */
 NS_IMETHODIMP
-nsDOMBlobBuilder::Append(const jsval& aData, JSContext* aCx)
+nsDOMBlobBuilder::Append(const jsval& aData,
+                         const nsAString& aEndings, JSContext* aCx)
 {
   // We need to figure out what our jsval is
 
   // Is it an object?
   if (JSVAL_IS_OBJECT(aData)) {
     JSObject* obj = JSVAL_TO_OBJECT(aData);
     if (!obj) {
       // We got passed null.  Just do nothing.
       return NS_OK;
     }
 
     // Is it a Blob?
     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(
       nsContentUtils::XPConnect()->
         GetNativeOfWrapper(aCx, obj));
-    if (blob)
-      return AppendBlob(blob);
+    if (blob) {
+      // Flatten so that multipart blobs will never nest
+      nsDOMFileBase* file = static_cast<nsDOMFileBase*>(
+          static_cast<nsIDOMBlob*>(blob));
+      const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = file->GetSubBlobs();
+      if (subBlobs) {
+        return mBlobSet.AppendBlobs(*subBlobs);
+      } else {
+        return mBlobSet.AppendBlob(blob);
+      }
+    }
 
     // Is it an array buffer?
     if (js_IsArrayBuffer(obj)) {
       JSObject* buffer = js::ArrayBuffer::getArrayBuffer(obj);
       if (buffer)
-        return AppendArrayBuffer(buffer);
+        return mBlobSet.AppendArrayBuffer(buffer);
     }
   }
 
   // If it's not a Blob or an ArrayBuffer, coerce it to a string
   JSString* str = JS_ValueToString(aCx, aData);
   NS_ENSURE_TRUE(str, NS_ERROR_FAILURE);
 
-  return AppendString(str, aCx);
+  return mBlobSet.AppendString(str, aEndings.EqualsLiteral("native"), aCx);
 }
 
 nsresult NS_NewBlobBuilder(nsISupports* *aSupports)
 {
   nsDOMBlobBuilder* builder = new nsDOMBlobBuilder();
   return CallQueryInterface(builder, aSupports);
 }
--- a/content/base/src/nsDOMBlobBuilder.h
+++ b/content/base/src/nsDOMBlobBuilder.h
@@ -40,17 +40,18 @@
 
 #include "nsDOMFile.h"
 #include "CheckedInt.h"
 
 #include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
 
-class nsDOMMultipartFile : public nsDOMFileBase
+class nsDOMMultipartFile : public nsDOMFileBase,
+                           public nsIJSNativeInitializer
 {
 public:
   // Create as a file
   nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
                      const nsAString& aName,
                      const nsAString& aContentType)
     : nsDOMFileBase(aName, aContentType, UINT64_MAX),
       mBlobs(aBlobs)
@@ -60,45 +61,63 @@ public:
   // Create as a blob
   nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
                      const nsAString& aContentType)
     : nsDOMFileBase(aContentType, UINT64_MAX),
       mBlobs(aBlobs)
   {
   }
 
+  // Create as a blob to be later initialized
+  nsDOMMultipartFile()
+    : nsDOMFileBase(EmptyString(), UINT64_MAX)
+  {
+  }
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIJSNativeInitializer
+  NS_IMETHOD Initialize(nsISupports* aOwner,
+                        JSContext* aCx,
+                        JSObject* aObj,
+                        PRUint32 aArgc,
+                        jsval* aArgv);
+
   already_AddRefed<nsIDOMBlob>
   CreateSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType);
 
   NS_IMETHOD GetSize(PRUint64*);
   NS_IMETHOD GetInternalStream(nsIInputStream**);
 
+  // DOMClassInfo constructor (for Blob([b1, "foo"], { type: "image/png" }))
+  static nsresult
+  NewBlob(nsISupports* *aNewObject);
+
+  virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
+  GetSubBlobs() const { return &mBlobs; }
+
 protected:
   nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
 };
 
-class nsDOMBlobBuilder : public nsIDOMMozBlobBuilder
-{
+class BlobSet {
 public:
-  nsDOMBlobBuilder()
+  BlobSet()
     : mData(nsnull), mDataLen(0), mDataBufferLen(0)
   {}
 
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMMOZBLOBBUILDER
+  nsresult AppendVoidPtr(const void* aData, PRUint32 aLength);
+  nsresult AppendString(JSString* aString, bool nativeEOL, JSContext* aCx);
+  nsresult AppendBlob(nsIDOMBlob* aBlob);
+  nsresult AppendArrayBuffer(JSObject* aBuffer);
+  nsresult AppendBlobs(const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlob);
 
-  nsresult GetBlobInternal(const nsAString& aContentType,
-                           bool aClearBuffer, nsIDOMBlob** aBlob);
-  nsresult AppendVoidPtr(const void* aData, PRUint32 aLength);
+  nsTArray<nsCOMPtr<nsIDOMBlob> >& GetBlobs() { Flush(); return mBlobs; }
 
 protected:
-  nsresult AppendString(JSString* aString, JSContext* aCx);
-  nsresult AppendBlob(nsIDOMBlob* aBlob);
-  nsresult AppendArrayBuffer(JSObject* aBuffer);
-
   bool ExpandBufferSize(PRUint64 aSize)
   {
     if (mDataBufferLen >= mDataLen + aSize) {
       mDataLen += aSize;
       return true;
     }
 
     // Start at 1 or we'll loop forever.
@@ -135,9 +154,28 @@ protected:
   }
 
   nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
   void* mData;
   PRUint64 mDataLen;
   PRUint64 mDataBufferLen;
 };
 
+class nsDOMBlobBuilder : public nsIDOMMozBlobBuilder
+{
+public:
+  nsDOMBlobBuilder()
+    : mBlobSet()
+  {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMMOZBLOBBUILDER
+
+  nsresult AppendVoidPtr(const void* aData, PRUint32 aLength)
+  { return mBlobSet.AppendVoidPtr(aData, aLength); }
+
+  nsresult GetBlobInternal(const nsAString& aContentType,
+                           bool aClearBuffer, nsIDOMBlob** aBlob);
+protected:
+  BlobSet mBlobSet;
+};
+
 #endif
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -194,31 +194,29 @@ NS_IMPL_EVENT_HANDLER(nsDOMFileReader, l
 NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, abort, FileIOObject)
 NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, progress, FileIOObject)
 NS_IMPL_FORWARD_EVENT_HANDLER(nsDOMFileReader, error, FileIOObject)
 
 NS_IMETHODIMP
 nsDOMFileReader::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
                             PRUint32 argc, jsval *argv)
 {
-  mOwner = do_QueryInterface(aOwner);
-  if (!mOwner) {
+  nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aOwner);
+  if (!owner) {
     NS_WARNING("Unexpected nsIJSNativeInitializer owner");
     return NS_OK;
   }
 
+  BindToOwner(owner);
+
   // This object is bound to a |window|,
-  // so reset the principal and script context.
+  // so reset the principal.
   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aOwner);
   NS_ENSURE_STATE(scriptPrincipal);
   mPrincipal = scriptPrincipal->GetPrincipal();
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(sgo);
-  mScriptContext = sgo->GetContext();
-  NS_ENSURE_STATE(mScriptContext);
 
   return NS_OK; 
 }
 
 // nsIInterfaceRequestor
 
 NS_IMETHODIMP
 nsDOMFileReader::GetInterface(const nsIID & aIID, void **aResult)
--- a/content/base/src/nsEventSource.cpp
+++ b/content/base/src/nsEventSource.cpp
@@ -171,16 +171,26 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(EventSource)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(nsEventSource, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsEventSource, nsDOMEventTargetHelper)
 
+void
+nsEventSource::DisconnectFromOwner()
+{
+  nsDOMEventTargetHelper::DisconnectFromOwner();
+  NS_DISCONNECT_EVENT_HANDLER(Open)
+  NS_DISCONNECT_EVENT_HANDLER(Message)
+  NS_DISCONNECT_EVENT_HANDLER(Error)
+  Close();
+}
+
 //-----------------------------------------------------------------------------
 // nsEventSource::nsIEventSource
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsEventSource::GetUrl(nsAString& aURL)
 {
   aURL = mOriginalURL;
@@ -246,19 +256,16 @@ nsEventSource::Close()
 
   while (mMessagesToDispatch.GetSize() != 0) {
     delete static_cast<Message*>(mMessagesToDispatch.PopFront());
   }
 
   mSrc = nsnull;
   mFrozen = false;
 
-  mScriptContext = nsnull;
-  mOwner = nsnull;
-
   mUnicodeDecoder = nsnull;
 
   mReadyState = nsIEventSource::CLOSED;
 
   return NS_OK;
 }
 
 /**
@@ -273,23 +280,22 @@ nsEventSource::Init(nsIPrincipal* aPrinc
 {
   NS_ENSURE_ARG(aPrincipal);
 
   if (mReadyState != nsIEventSource::CONNECTING || !PrefEnabled()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   mPrincipal = aPrincipal;
-  mScriptContext = aScriptContext;
   mWithCredentials = aWithCredentials;
   if (aOwnerWindow) {
-    mOwner = aOwnerWindow->IsOuterWindow() ?
-      aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow;
+    BindToOwner(aOwnerWindow->IsOuterWindow() ?
+      aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow);
   } else {
-    mOwner = nsnull;
+    BindToOwner(aOwnerWindow);
   }
 
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
   JSContext* cx = nsnull;
   if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
     const char *filename;
     if (nsJSUtils::GetCallingLocation(cx, &filename, &mScriptLine)) {
@@ -297,27 +303,29 @@ nsEventSource::Init(nsIPrincipal* aPrinc
     }
 
     mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
   }
 
   // Get the load group for the page. When requesting we'll add ourselves to it.
   // This way any pending requests will be automatically aborted if the user
   // leaves the page.
-  if (mScriptContext) {
+  nsresult rv;
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  if (sc) {
     nsCOMPtr<nsIDocument> doc =
-      nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+      nsContentUtils::GetDocumentFromScriptContext(sc);
     if (doc) {
       mLoadGroup = doc->GetDocumentLoadGroup();
     }
   }
 
   // get the src
   nsCOMPtr<nsIURI> baseURI;
-  nsresult rv = GetBaseURI(getter_AddRefs(baseURI));
+  rv = GetBaseURI(getter_AddRefs(baseURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> srcURI;
   rv = NS_NewURI(getter_AddRefs(srcURI), aURL, nsnull, baseURI);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
 
   // we observe when the window freezes and thaws
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
@@ -452,17 +460,17 @@ nsEventSource::Observe(nsISupports* aSub
                        const char* aTopic,
                        const PRUnichar* aData)
 {
   if (mReadyState == nsIEventSource::CLOSED) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSubject);
-  if (!mOwner || window != mOwner) {
+  if (!GetOwner() || window != GetOwner()) {
     return NS_OK;
   }
 
   nsresult rv;
   if (strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) {
     rv = Freeze();
     NS_ASSERTION(rv, "Freeze() failed");
   } else if (strcmp(aTopic, DOM_WINDOW_THAWED_TOPIC) == 0) {
@@ -829,18 +837,18 @@ nsEventSource::GetInterface(const nsIID 
     nsCOMPtr<nsIPromptFactory> wwatch =
       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get the an auth prompter for our window so that the parenting
     // of the dialogs works as it should when using tabs.
 
     nsCOMPtr<nsIDOMWindow> window;
-    if (mOwner) {
-      window = mOwner->GetOuterWindow();
+    if (GetOwner()) {
+      window = GetOwner()->GetOuterWindow();
     }
 
     return wwatch->GetPrompt(window, aIID, aResult);
   }
 
   return QueryInterface(aIID, aResult);
 }
 
@@ -856,25 +864,27 @@ nsEventSource::GetBaseURI(nsIURI **aBase
 {
   NS_ENSURE_ARG_POINTER(aBaseURI);
 
   *aBaseURI = nsnull;
 
   nsCOMPtr<nsIURI> baseURI;
 
   // first we try from document->GetBaseURI()
+  nsresult rv;
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+    nsContentUtils::GetDocumentFromScriptContext(sc);
   if (doc) {
     baseURI = doc->GetBaseURI();
   }
 
   // otherwise we get from the doc's principal
   if (!baseURI) {
-    nsresult rv = mPrincipal->GetURI(getter_AddRefs(baseURI));
+    rv = mPrincipal->GetURI(getter_AddRefs(baseURI));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   NS_ENSURE_STATE(baseURI);
 
   baseURI.forget(aBaseURI);
   return NS_OK;
 }
@@ -1262,18 +1272,19 @@ nsEventSource::CheckCanRequestSrc(nsIURI
   nsresult rv = nsContentUtils::GetSecurityManager()->
     CheckLoadURIWithPrincipal(mPrincipal,
                               srcToTest,
                               aCheckURIFlags);
   isValidURI = NS_SUCCEEDED(rv);
 
   // After the security manager, the content-policy check
 
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+    nsContentUtils::GetDocumentFromScriptContext(sc);
 
   // mScriptContext should be initialized because of GetBaseURI() above.
   // Still need to consider the case that doc is nsnull however.
   rv = CheckInnerWindowCorrectness();
   NS_ENSURE_SUCCESS(rv, false);
   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_DATAREQUEST,
                                  srcToTest,
@@ -1413,17 +1424,17 @@ nsEventSource::DispatchAllMessageEvents(
   mGoingToDispatchAllMessages = false;
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
   // Let's play get the JSContext
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(mOwner);
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
   NS_ENSURE_TRUE(sgo,);
 
   nsIScriptContext* scriptContext = sgo->GetContext();
   NS_ENSURE_TRUE(scriptContext,);
 
   JSContext* cx = scriptContext->GetNativeContext();
   NS_ENSURE_TRUE(cx,);
 
--- a/content/base/src/nsEventSource.h
+++ b/content/base/src/nsEventSource.h
@@ -97,16 +97,17 @@ public:
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // Determine if preferences allow EventSource
   static bool PrefEnabled();
 
+  virtual void DisconnectFromOwner();
 protected:
   nsresult GetBaseURI(nsIURI **aBaseURI);
 
   nsresult SetupHttpChannel();
   nsresult InitChannelAndRequestEventSource();
   nsresult ResetConnection();
   nsresult DispatchFailConnection();
   nsresult SetReconnectionTimeout();
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -414,18 +414,19 @@ nsWebSocket::GetInterface(const nsIID &a
 
   if (mDisconnected)
     return NS_ERROR_FAILURE;
 
   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
       aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
     nsresult rv;
 
+    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     nsCOMPtr<nsIDocument> doc =
-      nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+      nsContentUtils::GetDocumentFromScriptContext(sc);
     if (!doc)
       return NS_ERROR_NOT_AVAILABLE;
 
     nsCOMPtr<nsIPromptFactory> wwatch =
       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsPIDOMWindow> outerWindow = doc->GetWindow();
@@ -530,16 +531,28 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIRequest)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebSocket)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(nsWebSocket, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsWebSocket, nsDOMEventTargetHelper)
 
+void
+nsWebSocket::DisconnectFromOwner()
+{
+  nsDOMEventTargetHelper::DisconnectFromOwner();
+  NS_DISCONNECT_EVENT_HANDLER(Open)
+  NS_DISCONNECT_EVENT_HANDLER(Message)
+  NS_DISCONNECT_EVENT_HANDLER(Close)
+  NS_DISCONNECT_EVENT_HANDLER(Error)
+  FailConnectionQuietly();
+  DontKeepAliveAnyMore();
+}
+
 //-----------------------------------------------------------------------------
 // nsWebSocket::nsIJSNativeInitializer methods:
 //-----------------------------------------------------------------------------
 
 /**
  * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
  * It is used for constructing our nsWebSocket from JavaScript. It expects a URL
  * string parameter and an optional protocol parameter which may be a string or
@@ -785,17 +798,17 @@ nsWebSocket::CreateAndDispatchMessageEve
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
   nsresult rv;
 
   rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv))
     return NS_OK;
 
   // Get the JSContext
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(mOwner);
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
   NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
 
   nsIScriptContext* scriptContext = sgo->GetContext();
   NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
 
   JSContext* cx = scriptContext->GetNativeContext();
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
@@ -1520,22 +1533,21 @@ nsWebSocket::Init(nsIPrincipal* aPrincip
 
   NS_ENSURE_ARG(aPrincipal);
 
   if (!PrefEnabled()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   mPrincipal = aPrincipal;
-  mScriptContext = aScriptContext;
   if (aOwnerWindow) {
-    mOwner = aOwnerWindow->IsOuterWindow() ?
-      aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow;
+    BindToOwner(aOwnerWindow->IsOuterWindow() ?
+                aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow);
   } else {
-    mOwner = nsnull;
+    BindToOwner(aOwnerWindow);
   }
 
   // Attempt to kill "ghost" websocket: but usually too early for check to fail
   rv = CheckInnerWindowCorrectness();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Shut down websocket if window is frozen or destroyed (only needed for
   // "ghost" websockets--see bug 696085)
@@ -1560,18 +1572,19 @@ nsWebSocket::Init(nsIPrincipal* aPrincip
 
     mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
   }
 
   // parses the url
   rv = ParseURL(PromiseFlatString(aURL));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   nsCOMPtr<nsIDocument> originDoc =
-    nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+    nsContentUtils::GetDocumentFromScriptContext(sc);
 
   // Don't allow https:// to open ws://
   if (!mSecure &&
       !Preferences::GetBool("network.websocket.allowInsecureFromHTTPS",
                             false)) {
     // Confirmed we are opening plain ws:// and want to prevent this from a
     // secure context (e.g. https). Check the security context of the document
     // associated with this script, which is the same as associated with mOwner.
@@ -1626,17 +1639,17 @@ nsWebSocket::Observe(nsISupports* aSubje
                      const PRUnichar* aData)
 {
   if ((mReadyState == nsIWebSocket::CLOSING) ||
       (mReadyState == nsIWebSocket::CLOSED)) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSubject);
-  if (!mOwner || window != mOwner) {
+  if (!GetOwner() || window != GetOwner()) {
     return NS_OK;
   }
 
   if ((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) ||
       (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0))
   {
     FailConnectionQuietly();
   }
@@ -1695,18 +1708,20 @@ nsWebSocket::Resume()
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsWebSocket::GetLoadGroup(nsILoadGroup **aLoadGroup)
 {
   *aLoadGroup = nsnull;
 
+  nsresult rv;
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+    nsContentUtils::GetDocumentFromScriptContext(sc);
 
   if (doc) {
     *aLoadGroup = doc->GetDocumentLoadGroup().get();  // already_AddRefed
   }
 
   return NS_OK;
 }
 
--- a/content/base/src/nsWebSocket.h
+++ b/content/base/src/nsWebSocket.h
@@ -107,16 +107,17 @@ public:
                               PRUint8 optional_argc);
   NS_IMETHOD RemoveEventListener(const nsAString& aType,
                                  nsIDOMEventListener* aListener,
                                  bool aUseCapture);
 
   // Determine if preferences allow WebSocket
   static bool PrefEnabled();
 
+  virtual void DisconnectFromOwner();
 protected:
   nsresult ParseURL(const nsString& aURL);
   nsresult EstablishConnection();
 
   // These methods when called can release the WebSocket object
   nsresult FailConnection(PRUint16 reasonCode,
                           const nsACString& aReasonString = EmptyCString());
   void     FailConnectionQuietly();
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -324,16 +324,29 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXHREventTarget)
   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequestEventTarget)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(nsXHREventTarget, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsXHREventTarget, nsDOMEventTargetHelper)
 
+void
+nsXHREventTarget::DisconnectFromOwner()
+{
+  nsDOMEventTargetHelper::DisconnectFromOwner();
+  NS_DISCONNECT_EVENT_HANDLER(Load)
+  NS_DISCONNECT_EVENT_HANDLER(Error)
+  NS_DISCONNECT_EVENT_HANDLER(Abort)
+  NS_DISCONNECT_EVENT_HANDLER(Load)
+  NS_DISCONNECT_EVENT_HANDLER(Progress)
+  NS_DISCONNECT_EVENT_HANDLER(Loadend)
+  NS_DISCONNECT_EVENT_HANDLER(Timeout)
+}
+
 NS_IMETHODIMP
 nsXHREventTarget::GetOnload(nsIDOMEventListener** aOnLoad)
 {
   return GetInnerEventListener(mOnLoadListener, aOnLoad);
 }
 
 NS_IMETHODIMP
 nsXHREventTarget::SetOnload(nsIDOMEventListener* aOnLoad)
@@ -484,17 +497,17 @@ nsXMLHttpRequest::RootResultArrayBuffer(
 }
 
 /**
  * This Init method is called from the factory constructor.
  */
 nsresult
 nsXMLHttpRequest::Init()
 {
-  // Set the original mScriptContext and mPrincipal, if available.
+  // Set the original mPrincipal, if available.
   // Get JSContext from stack.
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
 
   if (!stack) {
     return NS_OK;
   }
 
@@ -510,76 +523,60 @@ nsXMLHttpRequest::Init()
     nsresult rv = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   NS_ENSURE_STATE(subjectPrincipal);
   mPrincipal = subjectPrincipal;
 
   nsIScriptContext* context = GetScriptContextFromJSContext(cx);
   if (context) {
-    mScriptContext = context;
     nsCOMPtr<nsPIDOMWindow> window =
       do_QueryInterface(context->GetGlobalObject());
-    if (window) {
-      mOwner = window->GetCurrentInnerWindow();
-    }
+    BindToOwner(window ? window->GetCurrentInnerWindow() : nsnull);
   }
 
   return NS_OK;
 }
 /**
  * This Init method should only be called by C++ consumers.
  */
 NS_IMETHODIMP
 nsXMLHttpRequest::Init(nsIPrincipal* aPrincipal,
                        nsIScriptContext* aScriptContext,
                        nsPIDOMWindow* aOwnerWindow,
                        nsIURI* aBaseURI)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
-  // This object may have already been initialized in the other Init call above
-  // if JS was on the stack. Clear the old values for mScriptContext and mOwner
-  // if new ones are not supplied here.
-
   mPrincipal = aPrincipal;
-  mScriptContext = aScriptContext;
-  if (aOwnerWindow) {
-    mOwner = aOwnerWindow->GetCurrentInnerWindow();
-  }
-  else {
-    mOwner = nsnull;
-  }
+  BindToOwner(aOwnerWindow ? aOwnerWindow->GetCurrentInnerWindow() : nsnull);
   mBaseURI = aBaseURI;
 
   return NS_OK;
 }
 
 /**
  * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
  */
 NS_IMETHODIMP
 nsXMLHttpRequest::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
                              PRUint32 argc, jsval *argv)
 {
-  mOwner = do_QueryInterface(aOwner);
-  if (!mOwner) {
+  nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aOwner);
+  if (!owner) {
     NS_WARNING("Unexpected nsIJSNativeInitializer owner");
     return NS_OK;
   }
 
   // This XHR object is bound to a |window|,
   // so re-set principal and script context.
   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal = do_QueryInterface(aOwner);
   NS_ENSURE_STATE(scriptPrincipal);
   mPrincipal = scriptPrincipal->GetPrincipal();
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(sgo);
-  mScriptContext = sgo->GetContext();
-  NS_ENSURE_STATE(mScriptContext);
+  BindToOwner(owner);
   return NS_OK; 
 }
 
 void
 nsXMLHttpRequest::ResetResponse()
 {
   mResponseXML = nsnull;
   mResponseBody.Truncate();
@@ -700,16 +697,25 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XMLHttpRequest)
 NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
 
 NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequest, nsXHREventTarget)
 
+void
+nsXMLHttpRequest::DisconnectFromOwner()
+{
+  nsXHREventTarget::DisconnectFromOwner();
+  NS_DISCONNECT_EVENT_HANDLER(UploadProgress)
+  NS_DISCONNECT_EVENT_HANDLER(Readystatechange)
+  Abort();
+}
+
 NS_IMETHODIMP
 nsXMLHttpRequest::GetOnreadystatechange(nsIDOMEventListener * *aOnreadystatechange)
 {
   return
     nsXHREventTarget::GetInnerEventListener(mOnReadystatechangeListener,
                                             aOnreadystatechange);
 }
 
@@ -772,21 +778,21 @@ nsXMLHttpRequest::GetResponseXML(nsIDOMD
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
   if ((XML_HTTP_REQUEST_DONE & mState) && mResponseXML) {
     *aResponseXML = mResponseXML;
     NS_ADDREF(*aResponseXML);
   }
   if (mWarnAboutMultipartHtml) {
     mWarnAboutMultipartHtml = false;
-    LogMessage("HTMLMultipartXHRWarning", mOwner);
+    LogMessage("HTMLMultipartXHRWarning", GetOwner());
   }
   if (mWarnAboutSyncHtml) {
     mWarnAboutSyncHtml = false;
-    LogMessage("HTMLSyncXHRWarning", mOwner);
+    LogMessage("HTMLSyncXHRWarning", GetOwner());
   }
   return NS_OK;
 }
 
 /*
  * This piece copied from nsXMLDocument, we try to get the charset
  * from HTTP headers.
  */
@@ -818,17 +824,17 @@ nsXMLHttpRequest::DetectCharset()
   if (NS_FAILED(rv) || mResponseCharset.IsEmpty()) {
     // MS documentation states UTF-8 is default for responseText
     mResponseCharset.AssignLiteral("UTF-8");
   }
 
   if (mResponseType == XML_HTTP_RESPONSE_TYPE_JSON &&
       !mResponseCharset.EqualsLiteral("UTF-8")) {
     // The XHR spec says only UTF-8 is supported for responseType == "json"
-    LogMessage("JSONCharsetWarning", mOwner);
+    LogMessage("JSONCharsetWarning", GetOwner());
     mResponseCharset.AssignLiteral("UTF-8");
   }
 
   nsCOMPtr<nsICharsetConverterManager> ccm =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return ccm->GetUnicodeDecoderRaw(mResponseCharset.get(),
@@ -1039,19 +1045,19 @@ NS_IMETHODIMP nsXMLHttpRequest::SetRespo
 {
   // If the state is not OPENED or HEADERS_RECEIVED raise an
   // INVALID_STATE_ERR exception and terminate these steps.
   if (!(mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT |
                   XML_HTTP_REQUEST_HEADERS_RECEIVED)))
     return NS_ERROR_DOM_INVALID_STATE_ERR;
 
   // sync request is not allowed setting responseType in window context
-  if (mOwner &&
+  if (HasOrHasHadOwner() &&
       !(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
-    LogMessage("ResponseTypeSyncXHRWarning", mOwner);
+    LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   // Set the responseType attribute's value to the given value.
   if (aResponseType.IsEmpty()) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_DEFAULT;
   } else if (aResponseType.EqualsLiteral("arraybuffer")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER;
@@ -1474,22 +1480,25 @@ nsXMLHttpRequest::GetResponseHeader(cons
   }
 
   return rv;
 }
 
 already_AddRefed<nsILoadGroup>
 nsXMLHttpRequest::GetLoadGroup() const
 {
-  if (mState & XML_HTTP_REQUEST_BACKGROUND) {
+  if (mState & XML_HTTP_REQUEST_BACKGROUND) {                 
     return nsnull;
   }
 
+  nsresult rv = NS_ERROR_FAILURE;
+  nsIScriptContext* sc =
+    const_cast<nsXMLHttpRequest*>(this)->GetContextForEventHandlers(&rv);
   nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+    nsContentUtils::GetDocumentFromScriptContext(sc);
   if (doc) {
     return doc->GetDocumentLoadGroup();
   }
 
   return nsnull;
 }
 
 nsresult
@@ -1558,17 +1567,17 @@ nsXMLHttpRequest::DispatchProgressEvent(
     return;
   }
 
   progress->InitProgressEvent(aType, false, false, aLengthComputable,
                               aLoaded, (aTotal == LL_MAXUINT) ? 0 : aTotal);
 
   if (aUseLSEventWrapper) {
     nsCOMPtr<nsIDOMProgressEvent> xhrprogressEvent =
-      new nsXMLHttpProgressEvent(progress, aPosition, aTotalSize, mOwner);
+      new nsXMLHttpProgressEvent(progress, aPosition, aTotalSize, GetOwner());
     event = xhrprogressEvent;
   }
   aTarget->DispatchDOMEvent(nsnull, event, nsnull, nsnull);
   
   if (dispatchLoadend) {
     DispatchProgressEvent(aTarget, NS_LITERAL_STRING(LOADEND_STR),
                           aUseLSEventWrapper, aLengthComputable,
                           aLoaded, aTotal, aPosition, aTotalSize);
@@ -1661,28 +1670,28 @@ nsXMLHttpRequest::Open(const nsACString&
   // and MS IIS equivalent TRACK (see bug 381264)
   if (method.LowerCaseEqualsLiteral("trace") ||
       method.LowerCaseEqualsLiteral("track")) {
     return NS_ERROR_INVALID_ARG;
   }
 
   // sync request is not allowed using withCredential or responseType
   // in window context
-  if (!async && mOwner &&
+  if (!async && HasOrHasHadOwner() &&
       (mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS ||
        mTimeoutMilliseconds ||
        mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT)) {
     if (mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS) {
-      LogMessage("WithCredentialsSyncXHRWarning", mOwner);
+      LogMessage("WithCredentialsSyncXHRWarning", GetOwner());
     }
     if (mTimeoutMilliseconds) {
-      LogMessage("TimeoutSyncXHRWarning", mOwner);
+      LogMessage("TimeoutSyncXHRWarning", GetOwner());
     }
     if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT) {
-      LogMessage("ResponseTypeSyncXHRWarning", mOwner);
+      LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
     }
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   nsresult rv;
   nsCOMPtr<nsIURI> uri;
 
   if (mState & (XML_HTTP_REQUEST_OPENED |
@@ -1706,32 +1715,32 @@ nsXMLHttpRequest::Open(const nsACString&
   if (async) {
     mState |= XML_HTTP_REQUEST_ASYNC;
   } else {
     mState &= ~XML_HTTP_REQUEST_ASYNC;
   }
 
   mState &= ~XML_HTTP_REQUEST_MPART_HEADERS;
 
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIDocument> doc =
-    nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+    nsContentUtils::GetDocumentFromScriptContext(sc);
   
   nsCOMPtr<nsIURI> baseURI;
   if (mBaseURI) {
     baseURI = mBaseURI;
   }
   else if (doc) {
     baseURI = doc->GetBaseURI();
   }
 
   rv = NS_NewURI(getter_AddRefs(uri), url, nsnull, baseURI);
   if (NS_FAILED(rv)) return rv;
 
-  // mScriptContext should be initialized because of GetBaseURI() above.
-  // Still need to consider the case that doc is nsnull however.
   rv = CheckInnerWindowCorrectness();
   NS_ENSURE_SUCCESS(rv, rv);
   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XMLHTTPREQUEST,
                                  uri,
                                  mPrincipal,
                                  doc,
                                  EmptyCString(), //mime guess
@@ -2118,30 +2127,32 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ
     }
   } else {
     // The request failed, so we shouldn't be parsing anyway
     mState &= ~XML_HTTP_REQUEST_PARSEBODY;
   }
 
   if (mState & XML_HTTP_REQUEST_PARSEBODY) {
     nsCOMPtr<nsIURI> baseURI, docURI;
+    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+    NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIDocument> doc =
-      nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+      nsContentUtils::GetDocumentFromScriptContext(sc);
 
     if (doc) {
       docURI = doc->GetDocumentURI();
       baseURI = doc->GetBaseURI();
     }
 
     // Create an empty document from it.  Here we have to cheat a little bit...
     // Setting the base URI to |baseURI| won't work if the document has a null
     // principal, so use mPrincipal when creating the document, then reset the
     // principal.
     const nsAString& emptyStr = EmptyString();
-    nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(mOwner);
+    nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(GetOwner());
     rv = nsContentUtils::CreateDocument(emptyStr, emptyStr, nsnull, docURI,
                                         baseURI, mPrincipal, global,
                                         mIsHtml ? DocumentFlavorHTML :
                                                   DocumentFlavorLegacyGuess,
                                         getter_AddRefs(mResponseXML));
     NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIDocument> responseDoc = do_QueryInterface(mResponseXML);
     responseDoc->SetPrincipal(documentPrincipal);
@@ -2573,18 +2584,20 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
       // If the document's original URI (before any push/replaceStates) matches
       // our principal, then we use the document's current URI (after
       // push/replaceStates).  Otherwise (if the document is, say, a data:
       // URI), we just use the principal's URI.
 
       nsCOMPtr<nsIURI> principalURI;
       mPrincipal->GetURI(getter_AddRefs(principalURI));
 
+      nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+      NS_ENSURE_SUCCESS(rv, rv);
       nsCOMPtr<nsIDocument> doc =
-        nsContentUtils::GetDocumentFromScriptContext(mScriptContext);
+        nsContentUtils::GetDocumentFromScriptContext(sc);
 
       nsCOMPtr<nsIURI> docCurURI;
       nsCOMPtr<nsIURI> docOrigURI;
       if (doc) {
         docCurURI = doc->GetDocumentURI();
         docOrigURI = doc->GetOriginalURI();
       }
 
@@ -2831,19 +2844,19 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
   mWaitingForOnStopRequest = true;
 
   // If we're synchronous, spin an event loop here and wait
   if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
     mState |= XML_HTTP_REQUEST_SYNCLOOPING;
 
     nsCOMPtr<nsIDocument> suspendedDoc;
     nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
-    if (mOwner) {
+    if (GetOwner()) {
       nsCOMPtr<nsIDOMWindow> topWindow;
-      if (NS_SUCCEEDED(mOwner->GetTop(getter_AddRefs(topWindow)))) {
+      if (NS_SUCCEEDED(GetOwner()->GetTop(getter_AddRefs(topWindow)))) {
         nsCOMPtr<nsPIDOMWindow> suspendedWindow(do_QueryInterface(topWindow));
         if (suspendedWindow &&
             (suspendedWindow = suspendedWindow->GetCurrentInnerWindow())) {
           suspendedDoc = do_QueryInterface(suspendedWindow->GetExtantDocument());
           if (suspendedDoc) {
             suspendedDoc->SuppressEventHandling();
           }
           suspendedWindow->SuspendTimeouts(1, false);
@@ -3003,27 +3016,28 @@ NS_IMETHODIMP
 nsXMLHttpRequest::GetTimeout(PRUint32 *aTimeout)
 {
   *aTimeout = mTimeoutMilliseconds;
   return NS_OK;
 }
 NS_IMETHODIMP
 nsXMLHttpRequest::SetTimeout(PRUint32 aTimeout)
 {
-  if ((mState & (XML_HTTP_REQUEST_ASYNC | XML_HTTP_REQUEST_UNSENT)) || !mOwner) {
+  if ((mState & (XML_HTTP_REQUEST_ASYNC | XML_HTTP_REQUEST_UNSENT)) ||
+      !HasOrHasHadOwner()) {
     mTimeoutMilliseconds = aTimeout;
     if (mRequestSentTime) {
       StartTimeoutTimer();
     }
     return NS_OK;
   }
 
   /* Timeout is not supported for synchronous requests with an owning window,
      per XHR2 spec. */
-  LogMessage("TimeoutSyncXHRWarning", mOwner);
+  LogMessage("TimeoutSyncXHRWarning", GetOwner());
   return NS_ERROR_DOM_INVALID_ACCESS_ERR;
 }
 
 void
 nsXMLHttpRequest::StartTimeoutTimer()
 {
   NS_ABORT_IF_FALSE(mRequestSentTime,
                     "StartTimeoutTimer mustn't be called before the request was sent!");
@@ -3161,19 +3175,19 @@ NS_IMETHODIMP
 nsXMLHttpRequest::SetWithCredentials(bool aWithCredentials)
 {
   // Return error if we're already processing a request
   if (XML_HTTP_REQUEST_SENT & mState) {
     return NS_ERROR_FAILURE;
   }
 
   // sync request is not allowed setting withCredentials in window context
-  if (mOwner &&
+  if (HasOrHasHadOwner() &&
       !(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
-    LogMessage("WithCredentialsSyncXHRWarning", mOwner);
+    LogMessage("WithCredentialsSyncXHRWarning", GetOwner());
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   if (aWithCredentials) {
     mState |= XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
   }
   else {
     mState &= ~XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
@@ -3514,18 +3528,18 @@ nsXMLHttpRequest::GetInterface(const nsI
     nsCOMPtr<nsIPromptFactory> wwatch =
       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get the an auth prompter for our window so that the parenting
     // of the dialogs works as it should when using tabs.
 
     nsCOMPtr<nsIDOMWindow> window;
-    if (mOwner) {
-      window = mOwner->GetOuterWindow();
+    if (GetOwner()) {
+      window = GetOwner()->GetOuterWindow();
     }
 
     return wwatch->GetPrompt(window, aIID,
                              reinterpret_cast<void**>(aResult));
 
   }
 
   return QueryInterface(aIID, aResult);
@@ -3536,17 +3550,17 @@ nsXMLHttpRequest::GetUpload(nsIXMLHttpRe
 {
   *aUpload = nsnull;
 
   nsresult rv;
   nsIScriptContext* scriptContext =
     GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!mUpload) {
-    mUpload = new nsXMLHttpRequestUpload(mOwner, scriptContext);
+    mUpload = new nsXMLHttpRequestUpload(this);
     NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY);
   }
   NS_ADDREF(*aUpload = mUpload);
   return NS_OK;
 }
 
 void
 nsXMLHttpRequest::HandleTimeoutCallback()
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -78,36 +78,35 @@ class nsXHREventTarget : public nsDOMEve
 public:
   virtual ~nsXHREventTarget() {}
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXHREventTarget,
                                            nsDOMEventTargetHelper)
   NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
+  virtual void DisconnectFromOwner();
 protected:
   nsRefPtr<nsDOMEventListenerWrapper> mOnLoadListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnAbortListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnLoadStartListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnProgressListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnLoadendListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnTimeoutListener;
 };
 
 class nsXMLHttpRequestUpload : public nsXHREventTarget,
                                public nsIXMLHttpRequestUpload
 {
 public:
-  nsXMLHttpRequestUpload(nsPIDOMWindow* aOwner,
-                         nsIScriptContext* aScriptContext)
+  nsXMLHttpRequestUpload(nsDOMEventTargetHelper* aOwner)
   {
-    mOwner = aOwner;
-    mScriptContext = aScriptContext;
-  }
+    BindToOwner(aOwner);
+  }                                         
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
   NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
   NS_DECL_NSIXMLHTTPREQUESTUPLOAD
 
   bool HasListeners()
   {
     return mListenerManager && mListenerManager->HasListeners();
@@ -201,17 +200,18 @@ public:
   nsresult Init();
 
   void SetRequestObserver(nsIRequestObserver* aObserver);
 
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(nsXMLHttpRequest,
                                                                    nsXHREventTarget)
   bool AllowUploadProgress();
   void RootResultArrayBuffer();
-  
+
+  virtual void DisconnectFromOwner();
 protected:
   friend class nsMultipartProxyListener;
 
   nsresult DetectCharset();
   nsresult AppendToResponseText(const char * aBuffer, PRUint32 aBufferLen);
   static NS_METHOD StreamReaderFunc(nsIInputStream* in,
                 void* closure,
                 const char* fromRawSegment,
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -479,16 +479,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug628938.html \
 		test_bug626262.html \
 		test_plugin_freezing.html \
 		test_bug638112.html \
 		bug638112-response.txt \
 		bug638112.sjs \
 		test_bug656283.html \
 		test_blobbuilder.html \
+		test_blobconstructor.html \
 		fileutils.js \
 		test_bug338583.html \
 		test_EventSource_redirects.html \
 		eventsource.resource \
 		eventsource.resource^headers^ \
 		eventsource_redirect.resource \
 		eventsource_redirect.resource^headers^ \
 		eventsource_redirect_to.resource \
--- a/content/base/test/fileutils.js
+++ b/content/base/test/fileutils.js
@@ -92,18 +92,18 @@ function getXHRLoadHandler(expectedResul
   return function (event) {
     is(event.target.readyState, 4,
        "[XHR] readyState in test " + testName);
     if (statusWorking) {
       is(event.target.status, 200,
          "[XHR] no error in test " + testName);
     }
     else {
-      todo(event.target.status, 200,
-           "[XHR] no error in test " + testName);
+      todo_is(event.target.status, 200,
+              "[XHR] no error in test " + testName);
     }
     // Do not use |is(convertXHRBinary(event.target.responseText), expectedResult, "...");| that may output raw binary data.
     var convertedData = convertXHRBinary(event.target.responseText);
     is(convertedData.length, expectedResult.length,
        "[XHR] Length of result in test " + testName);
     ok(convertedData == expectedResult,
        "[XHR] Content of result in test " + testName);
     is(event.lengthComputable, true,
--- a/content/base/test/test_blobbuilder.html
+++ b/content/base/test/test_blobbuilder.html
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=648997">Mozilla Bug 648997</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.7">
-
+"use strict";
 // We're prefixing still
 window.BlobBuilder = window.MozBlobBuilder;
 
 /** Test for Bug 648997 **/
 var blobBuilder = BlobBuilder();
 ok(blobBuilder, "BlobBuilder should exist");
 
 ok(blobBuilder.append, "BlobBuilder should have an append method");
@@ -84,69 +84,97 @@ let aB = new ArrayBuffer(16);
 var int8View = new Int8Array(aB);
 for (var i = 0; i < 16; i++) {
   int8View[i] = i+65;
 }
 
 let testData = 
  [
     // Test 3 strings
-    [["foo", "bar", "baz"], [{start: 0, length: 9, contents: "foobarbaz"},
+    [["foo", "bar", "baz"], undefined,
+                            [{start: 0, length: 9, contents: "foobarbaz"},
                              {start: 0, length: 3, contents: "foo"},
                              {start: 3, length:6, contents:  "barbaz"},
                              {start: 6, length: 3, contents:  "baz"},
                              {start: 6, length: 6, contents: "baz"},
                              {start: 0, length: 9, contents:  "foobarbaz"},
                              {start: 0, length: 11, contents: "foobarbaz"},
                              {start: 10, length: 5, contents: ""}]],
     // Test string, Blob, string
-    [["foo", blob1, "baz"], [{start: 0, length: 3, contents:  "foo"},
+    [["foo", blob1, "baz"], undefined,
+                            [{start: 0, length: 3, contents:  "foo"},
                              {start: 3, length: 8, contents:  "squiggle"},
                              {start: 2, length: 2, contents:  "os"},
                              {start: 10, length: 2, contents: "eb"}]],
     // Test blob, string, blob
-    [[blob1, "foo", blob1], [{start: 0, length: 8, contents:  "squiggle"},
+    [[blob1, "foo", blob1], undefined,
+                            [{start: 0, length: 8, contents:  "squiggle"},
                              {start: 7, length: 2, contents:  "ef"},
                              {start: 10, length: 2, contents: "os"},
                              {start: 1, length: 3, contents:  "qui"},
                              {start: 12, length: 3, contents: "qui"},
                              {start: 40, length: 20, contents: ""}]],
     // Test blobs all the way down
-    [[blob2, blob1, blob2], [{start: 0, length: 4, contents:  "ohai"},
+    [[blob2, blob1, blob2], undefined,
+                            [{start: 0, length: 4, contents:  "ohai"},
                              {start: 4, length: 8, contents:  "squiggle"},
                              {start: 12, length: 4, contents: "ohai"},
                              {start: 1, length: 2, contents:  "ha"},
                              {start: 5, length: 4, contents:  "quig"}]],
     // Test an array buffer
-    [[aB, blob1, "foo"],    [{start: 0, length: 8, contents:  "ABCDEFGH"},
+    [[aB, blob1, "foo"], null,
+                            [{start: 0, length: 8, contents:  "ABCDEFGH"},
                              {start: 8, length:10, contents:  "IJKLMNOPsq"},
                              {start: 17, length: 3, contents: "qui"},
                              {start: 4, length: 8, contents:  "EFGHIJKL"}]],
+    // Test transparent line endings
+    [["foo\r\n", "bar\r", "baz\n"], { endings: "transparent" },
+                            [{start: 0, length: 5, contents:  "foo\r\n"},
+                             {start: 5, length: 4, contents:  "bar\r"},
+                             {start: 9, length: 4, contents: "baz\n"}]],
+    // Test transparent line endings when the second argument is omitted
+    [["foo\r\n", "bar\r", "baz\n"], undefined,
+                            [{start: 0, length: 5, contents:  "foo\r\n"},
+                             {start: 5, length: 4, contents:  "bar\r"},
+                             {start: 9, length: 4, contents: "baz\n"}]],
+    // Test native line endings
+    [["foo\r\n", "bar\r", "baz\n"], { endings: "native" },
+                            navigator.platform.indexOf("Win") != -1 ?
+                            [{start: 0, length: 5, contents:  "foo\r\n"},
+                             {start: 5, length: 5, contents:  "bar\r\n"},
+                             {start: 10, length: 5, contents: "baz\r\n"}] :
+                            [{start: 0, length: 4, contents:  "foo\n"},
+                             {start: 4, length: 4, contents:  "bar\n"},
+                             {start: 8, length: 4, contents: "baz\n"}]],
     // Test type coercion of a number
-    [[3, aB, "foo"],        [{start: 0, length: 8, contents:  "3ABCDEFG"},
+    [[3, aB, "foo"], {},    [{start: 0, length: 8, contents:  "3ABCDEFG"},
                              {start: 8, length:10, contents:  "HIJKLMNOPf"},
                              {start: 17, length: 4, contents: "foo"},
                              {start: 4, length: 8, contents:  "DEFGHIJK"}]]
  ];
 
 let testCounter = 0;
 
 function doTest(data) {
   testCounter++;
 
-  [blobs, tests] = data;
+  [blobs, options, tests] = data;
 
   function runTest(test) {
 
     let bb = new BlobBuilder();
     ok(bb, "BlobBuilder should exist");
 
     function doAppend(blob) {
-      bb.append(blob);
-	  blob.expando = bb; // Do we leak?
+      if (options !== undefined) {
+        bb.append(blob, options && options.endings);
+      } else {
+        bb.append(blob);
+      }
+      blob.expando = bb; // Do we leak?
     }
 
     blobs.forEach(doAppend);
     ok(true, "Test " + testCounter + " appended all successfully");
     let blob = bb.getBlob();
     ok(blob, "Test " + testCounter + " got blob");
     ok(blob instanceof Blob, "Test " + testCounter + " blob is a Blob");
     ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File");
copy from content/base/test/test_blobbuilder.html
copy to content/base/test/test_blobconstructor.html
--- a/content/base/test/test_blobbuilder.html
+++ b/content/base/test/test_blobconstructor.html
@@ -1,171 +1,192 @@
 <!DOCTYPE HTML>
 <html>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=648997
+https://bugzilla.mozilla.org/show_bug.cgi?id=721569
 -->
 <head>
-  <title>Test for Bug 648997</title>
+  <title>Test for Blob constructor (Bug 721569)</title>
   <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="fileutils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=648997">Mozilla Bug 648997</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=721569">Mozilla Bug 721569</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript;version=1.7">
-
-// We're prefixing still
-window.BlobBuilder = window.MozBlobBuilder;
+"use strict";
+/** Test for Bug 721569 **/
+var blob = Blob();
+ok(blob, "Blob should exist");
 
-/** Test for Bug 648997 **/
-var blobBuilder = BlobBuilder();
-ok(blobBuilder, "BlobBuilder should exist");
+ok(blob.size !== undefined, "Blob should have a size property");
+ok(blob.type !== undefined, "Blob should have a type property");
+ok(blob.slice, "Blob should have a slice method");
 
-ok(blobBuilder.append, "BlobBuilder should have an append method");
-ok(blobBuilder.getBlob, "BlobBuilder should have a getBlob method");
-ok(blobBuilder.getFile, "BlobBuilder should have a getFile method");
+blob = Blob([], {type: null});
+ok(blob, "Blob should exist");
+is(blob.type, "null", "Blob type should be stringified");
+
+blob = Blob([], {type: undefined});
+ok(blob, "Blob should exist");
+is(blob.type, "undefined", "Blob type should be stringified");
 
 try {
-blobBuilder.append();
+blob = Blob([]);
+ok(true, "an empty blobParts argument should not throw");
+} catch(e) {
 ok(false, "NOT REACHED");
-} catch(e) {
-ok(true, "an empty argument to append should throw");
 }
 
-blobBuilder.append(null);
-// Yay we didn't crash.
+try {
+blob = Blob(null);
+ok(false, "NOT REACHED");
+} catch(e) {
+ok(true, "a null blobParts member should throw");
+}
 
-blobBuilder.append("squiggle");
-let blob1 = blobBuilder.getBlob();
-ok(blob1 instanceof Blob, "getBlob should produce Blobs");
-ok(!(blob1 instanceof File), "getBlob should not produce Files");
-is(blob1.type, "", "getBlob with no argument should return Blob with empty type");
-is(blob1.size, 8, "getBlob should return Blob with correct size");
-
-blobBuilder.append("ohai");
-let blob2 = blobBuilder.getFile("thefilename");
-ok(blob2 instanceof Blob, "getFile should produce Blobs");
-ok(blob2 instanceof File, "getFile should produce Files");
-is(blob2.name, "thefilename", "getFile should produces Files with correct name");
-is(blob2.type, "", "getFile with no second argument should return File with empty type");
-is(blob2.size, 4, "getFile should return Blob with correct size");
+try {
+blob = Blob([], null);
+ok(false, "NOT REACHED");
+} catch(e) {
+ok(true, "a null options member should throw");
+}
 
-blobBuilder.append("steak");
-let blob3 = blobBuilder.getBlob("content/type");
-ok(blob3 instanceof Blob, "getBlob should produce Blobs");
-ok(!(blob3 instanceof File), "getBlob should not produce Files");
-is(blob3.type, "content/type", "getBlob with no argument should return Blob with empty type");
-is(blob3.size, 5, "getBlob should return Blob with correct size");
+try {
+blob = Blob([], undefined);
+ok(false, "NOT REACHED");
+} catch(e) {
+ok(true, "an undefined options member should throw");
+}
 
-blobBuilder.append("apples");
-let blob4 = blobBuilder.getFile("the other filename", "text/plain");
-ok(blob4 instanceof Blob, "getFile should produce Blobs");
-ok(blob4 instanceof File, "getFile should produce Files");
-is(blob4.name, "the other filename", "getFile should produces Files with correct name");
-is(blob4.type, "text/plain", "getFile with second argument should return File with correct type");
-is(blob4.size, 6, "getFile should return Blob with correct size");
+let blob1 = Blob(["squiggle"]);
+ok(blob1 instanceof Blob, "Blob constructor should produce Blobs");
+ok(!(blob1 instanceof File), "Blob constructor should not produce Files");
+is(blob1.type, "", "Blob constructor with no options should return Blob with empty type");
+is(blob1.size, 8, "Blob constructor should return Blob with correct size");
 
-blobBuilder.append("boletes");
-let blob5 = blobBuilder.getFile("");
-ok(blob5 instanceof Blob, "getFile should produce Blobs");
-ok(blob5 instanceof File, "getFile should produce Files");
-is(blob5.name, "", "getFile with empty name should produces Files with empty name");
-is(blob5.type, "", "getFile with no second argument should return File with correct type");
-is(blob5.size, 7, "getFile should return Blob with correct size");
-testFile(blob5, "boletes", "Test empty-named File from BlobBuilder.getFile");
+let blob2 = Blob(["steak"], {type: "content/type"});
+ok(blob2 instanceof Blob, "Blob constructor should produce Blobs");
+ok(!(blob2 instanceof File), "Blob constructor should not produce Files");
+is(blob2.type, "content/type", "Blob constructor with a type option should return Blob with the type");
+is(blob2.size, 5, "Blob constructor should return Blob with correct size");
 
 
 let aB = new ArrayBuffer(16);
 var int8View = new Int8Array(aB);
 for (var i = 0; i < 16; i++) {
   int8View[i] = i+65;
 }
 
 let testData = 
  [
     // Test 3 strings
-    [["foo", "bar", "baz"], [{start: 0, length: 9, contents: "foobarbaz"},
+    [["foo", "bar", "baz"], {},
+                            [{start: 0, length: 9, contents: "foobarbaz"},
                              {start: 0, length: 3, contents: "foo"},
                              {start: 3, length:6, contents:  "barbaz"},
                              {start: 6, length: 3, contents:  "baz"},
                              {start: 6, length: 6, contents: "baz"},
                              {start: 0, length: 9, contents:  "foobarbaz"},
                              {start: 0, length: 11, contents: "foobarbaz"},
                              {start: 10, length: 5, contents: ""}]],
     // Test string, Blob, string
-    [["foo", blob1, "baz"], [{start: 0, length: 3, contents:  "foo"},
+    [["foo", blob1, "baz"], {},
+                            [{start: 0, length: 3, contents:  "foo"},
                              {start: 3, length: 8, contents:  "squiggle"},
                              {start: 2, length: 2, contents:  "os"},
                              {start: 10, length: 2, contents: "eb"}]],
     // Test blob, string, blob
-    [[blob1, "foo", blob1], [{start: 0, length: 8, contents:  "squiggle"},
+    [[blob1, "foo", blob1], {},
+                            [{start: 0, length: 8, contents:  "squiggle"},
                              {start: 7, length: 2, contents:  "ef"},
                              {start: 10, length: 2, contents: "os"},
                              {start: 1, length: 3, contents:  "qui"},
                              {start: 12, length: 3, contents: "qui"},
                              {start: 40, length: 20, contents: ""}]],
     // Test blobs all the way down
-    [[blob2, blob1, blob2], [{start: 0, length: 4, contents:  "ohai"},
-                             {start: 4, length: 8, contents:  "squiggle"},
-                             {start: 12, length: 4, contents: "ohai"},
-                             {start: 1, length: 2, contents:  "ha"},
-                             {start: 5, length: 4, contents:  "quig"}]],
+    [[blob2, blob1, blob2], {},
+                            [{start: 0, length: 5, contents:  "steak"},
+                             {start: 5, length: 8, contents:  "squiggle"},
+                             {start: 13, length: 5, contents: "steak"},
+                             {start: 1, length: 2, contents:  "te"},
+                             {start: 6, length: 4, contents:  "quig"}]],
     // Test an array buffer
-    [[aB, blob1, "foo"],    [{start: 0, length: 8, contents:  "ABCDEFGH"},
+    [[aB, blob1, "foo"], {},
+                            [{start: 0, length: 8, contents:  "ABCDEFGH"},
                              {start: 8, length:10, contents:  "IJKLMNOPsq"},
                              {start: 17, length: 3, contents: "qui"},
                              {start: 4, length: 8, contents:  "EFGHIJKL"}]],
+    // Test transparent line endings
+    [["foo\r\n", "bar\r", "baz\n"], { endings: "transparent" },
+                            [{start: 0, length: 5, contents:  "foo\r\n"},
+                             {start: 5, length: 4, contents:  "bar\r"},
+                             {start: 9, length: 4, contents: "baz\n"}]],
+    // Test transparent line endings when the second argument is omitted
+    [["foo\r\n", "bar\r", "baz\n"], undefined,
+                            [{start: 0, length: 5, contents:  "foo\r\n"},
+                             {start: 5, length: 4, contents:  "bar\r"},
+                             {start: 9, length: 4, contents: "baz\n"}]],
+    // Test native line endings
+    [["foo\r\n", "bar\r", "baz\n"], { endings: "native" },
+                            navigator.platform.indexOf("Win") != -1 ?
+                            [{start: 0, length: 5, contents:  "foo\r\n"},
+                             {start: 5, length: 5, contents:  "bar\r\n"},
+                             {start: 10, length: 5, contents: "baz\r\n"}] :
+                            [{start: 0, length: 4, contents:  "foo\n"},
+                             {start: 4, length: 4, contents:  "bar\n"},
+                             {start: 8, length: 4, contents: "baz\n"}]],
     // Test type coercion of a number
-    [[3, aB, "foo"],        [{start: 0, length: 8, contents:  "3ABCDEFG"},
-                             {start: 8, length:10, contents:  "HIJKLMNOPf"},
-                             {start: 17, length: 4, contents: "foo"},
-                             {start: 4, length: 8, contents:  "DEFGHIJK"}]]
+    [[3, aB, "foo"], {},    "InvalidStateError"]
  ];
 
 let testCounter = 0;
 
 function doTest(data) {
   testCounter++;
 
-  [blobs, tests] = data;
+  [blobs, options, tests] = data;
 
   function runTest(test) {
 
-    let bb = new BlobBuilder();
-    ok(bb, "BlobBuilder should exist");
-
-    function doAppend(blob) {
-      bb.append(blob);
-	  blob.expando = bb; // Do we leak?
+    let blob;
+    if (options !== undefined) {
+      blob = new Blob(blobs, options);
+    } else {
+      blob = new Blob(blobs);
     }
-
-    blobs.forEach(doAppend);
-    ok(true, "Test " + testCounter + " appended all successfully");
-    let blob = bb.getBlob();
     ok(blob, "Test " + testCounter + " got blob");
     ok(blob instanceof Blob, "Test " + testCounter + " blob is a Blob");
     ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File");
 
     let slice = blob.slice(test.start, test.start + test.length);
     ok(slice, "Test " + testCounter + " got slice");
     ok(slice instanceof Blob, "Test " + testCounter + " slice is a Blob");
     ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File");
     is(slice.size, test.contents.length,
        "Test " + testCounter + " slice is correct size");
 
     testFile(slice, test.contents, "Test " + testCounter);
   }
-  tests.forEach(runTest);
+  if (Array.isArray(tests)) {
+    tests.forEach(runTest);
+  } else {
+    try {
+      let blob = new Blob(blobs, options);
+      ok(false, "NOT REACHED");
+    } catch (e) {
+      is(e.name, tests, "Blob constructor should throw " + tests);
+    }
+  }
   SpecialPowers.gc();
 }
 
 SimpleTest.waitForExplicitFinish();
 testData.forEach(doTest);
 
 </script>
 </pre>
--- a/content/events/src/nsDOMEventTargetHelper.cpp
+++ b/content/events/src/nsDOMEventTargetHelper.cpp
@@ -39,16 +39,17 @@
 #include "nsDOMEventTargetHelper.h"
 #include "nsContentUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsGUIEvent.h"
 #include "nsIDocument.h"
 #include "nsIJSContextStack.h"
 #include "nsDOMJSUtils.h"
 #include "prprf.h"
+#include "nsGlobalWindow.h"
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventListenerWrapper)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventListenerWrapper)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
 NS_INTERFACE_MAP_END_AGGREGATED(mListener)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMEventListenerWrapper)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMEventListenerWrapper)
@@ -86,46 +87,89 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
                               name);
   } else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDOMEventTargetHelper, tmp->mRefCnt.get())
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mListenerManager,
                                                   nsEventListenerManager)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventTargetHelper)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMEventTargetHelper)
 
 NS_IMPL_DOMTARGET_DEFAULTS(nsDOMEventTargetHelper);
 
 nsDOMEventTargetHelper::~nsDOMEventTargetHelper()
 {
+  if (mOwner) {
+    static_cast<nsGlobalWindow*>(mOwner)->RemoveEventTargetObject(this);
+  }
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
   nsContentUtils::ReleaseWrapper(this, this);
 }
 
+void
+nsDOMEventTargetHelper::BindToOwner(nsPIDOMWindow* aOwner)
+{
+  if (mOwner) {
+    static_cast<nsGlobalWindow*>(mOwner)->RemoveEventTargetObject(this);
+    mOwner = nsnull;
+    mHasOrHasHadOwner = false;
+  }
+  if (aOwner) {
+    mOwner = aOwner;
+    mHasOrHasHadOwner = true;
+    static_cast<nsGlobalWindow*>(mOwner)->AddEventTargetObject(this);
+  }
+}
+
+void
+nsDOMEventTargetHelper::BindToOwner(nsDOMEventTargetHelper* aOther)
+{
+  if (mOwner) {
+    static_cast<nsGlobalWindow*>(mOwner)->RemoveEventTargetObject(this);
+    mOwner = nsnull;
+    mHasOrHasHadOwner = false;
+  }
+  if (aOther) {
+    mHasOrHasHadOwner = aOther->HasOrHasHadOwner();
+    if (aOther->GetOwner()) {
+      mOwner = aOther->GetOwner();
+      mHasOrHasHadOwner = true;
+      static_cast<nsGlobalWindow*>(mOwner)->AddEventTargetObject(this);
+    }
+  }
+}
+
+void
+nsDOMEventTargetHelper::DisconnectFromOwner()
+{
+  mOwner = nsnull;
+  // Event listeners can't be handled anymore, so we can release them here.
+  if (mListenerManager) {
+    mListenerManager->Disconnect();
+    mListenerManager = nsnull;
+  }
+}
+
 NS_IMETHODIMP
 nsDOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
                                             nsIDOMEventListener* aListener,
                                             bool aUseCapture)
 {
   nsEventListenerManager* elm = GetListenerManager(false);
   if (elm) {
     elm->RemoveEventListener(aType, aListener, aUseCapture);
@@ -217,17 +261,17 @@ nsDOMEventTargetHelper::RemoveAddEventLi
 }
 
 nsresult
 nsDOMEventTargetHelper::GetInnerEventListener(nsRefPtr<nsDOMEventListenerWrapper>& aWrapper,
                                               nsIDOMEventListener** aListener)
 {
   NS_ENSURE_ARG_POINTER(aListener);
   if (aWrapper) {
-    NS_ADDREF(*aListener = aWrapper->GetInner());
+    NS_IF_ADDREF(*aListener = aWrapper->GetInner());
   } else {
     *aListener = nsnull;
   }
   return NS_OK;
 }
 
 
 nsresult
@@ -267,36 +311,36 @@ nsDOMEventTargetHelper::GetListenerManag
 
 nsIScriptContext*
 nsDOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
 {
   *aRv = CheckInnerWindowCorrectness();
   if (NS_FAILED(*aRv)) {
     return nsnull;
   }
-  return mScriptContext;
+  return mOwner ? static_cast<nsGlobalWindow*>(mOwner)->GetContextInternal()
+                : nsnull;
 }
 
 void
 nsDOMEventTargetHelper::Init(JSContext* aCx)
 {
-  // Set the original mScriptContext and mPrincipal, if available
   JSContext* cx = aCx;
   if (!cx) {
     nsIJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
 
     if (!stack)
       return;
 
     if (NS_FAILED(stack->Peek(&cx)) || !cx)
       return;
   }
 
   NS_ASSERTION(cx, "Should have returned earlier ...");
   nsIScriptContext* context = GetScriptContextFromJSContext(cx);
   if (context) {
-    mScriptContext = context;
     nsCOMPtr<nsPIDOMWindow> window =
       do_QueryInterface(context->GetGlobalObject());
-    if (window)
-      mOwner = window->GetCurrentInnerWindow();
+    if (window) {
+      BindToOwner(window->GetCurrentInnerWindow());
+    }
   }
 }
--- a/content/events/src/nsDOMEventTargetHelper.h
+++ b/content/events/src/nsDOMEventTargetHelper.h
@@ -57,25 +57,26 @@ public:
   : mListener(aListener) {}
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMEventListenerWrapper)
 
   NS_DECL_NSIDOMEVENTLISTENER
 
   nsIDOMEventListener* GetInner() { return mListener; }
+  void Disconnect() { mListener = nsnull; }
 protected:
   nsCOMPtr<nsIDOMEventListener> mListener;
 };
 
 class nsDOMEventTargetHelper : public nsIDOMEventTarget,
                                public nsWrapperCache
 {
 public:
-  nsDOMEventTargetHelper() {}
+  nsDOMEventTargetHelper() : mOwner(nsnull), mHasOrHasHadOwner(false) {}
   virtual ~nsDOMEventTargetHelper();
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMEventTargetHelper)
 
   NS_DECL_NSIDOMEVENTTARGET
 
   void GetParentObject(nsIScriptGlobalObject **aParentObject)
   {
@@ -116,30 +117,38 @@ public:
                                   nsRefPtr<nsDOMEventListenerWrapper>& aCurrent,
                                   nsIDOMEventListener* aNew);
 
   nsresult GetInnerEventListener(nsRefPtr<nsDOMEventListenerWrapper>& aWrapper,
                                  nsIDOMEventListener** aListener);
 
   nsresult CheckInnerWindowCorrectness()
   {
+    NS_ENSURE_STATE(!mHasOrHasHadOwner || mOwner);
     if (mOwner) {
       NS_ASSERTION(mOwner->IsInnerWindow(), "Should have inner window here!\n");
       nsPIDOMWindow* outer = mOwner->GetOuterWindow();
       if (!outer || outer->GetCurrentInnerWindow() != mOwner) {
         return NS_ERROR_FAILURE;
       }
     }
     return NS_OK;
   }
+
+  void BindToOwner(nsPIDOMWindow* aOwner);
+  void BindToOwner(nsDOMEventTargetHelper* aOther);
+  virtual void DisconnectFromOwner();                   
+  nsPIDOMWindow* GetOwner() { return mOwner; }
+  bool HasOrHasHadOwner() { return mHasOrHasHadOwner; }
 protected:
   nsRefPtr<nsEventListenerManager> mListenerManager;
+private:
   // These may be null (native callers or xpcshell).
-  nsCOMPtr<nsIScriptContext> mScriptContext;
-  nsCOMPtr<nsPIDOMWindow>    mOwner; // Inner window.
+  nsPIDOMWindow*             mOwner; // Inner window.
+  bool                       mHasOrHasHadOwner;
 };
 
 #define NS_DECL_EVENT_HANDLER(_event)                                         \
   protected:                                                                  \
     nsRefPtr<nsDOMEventListenerWrapper> mOn##_event##Listener;                \
   public:
 
 #define NS_DECL_AND_IMPL_EVENT_HANDLER(_event)                                \
@@ -182,16 +191,19 @@ protected:
     }
 
 #define NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(_event)                    \
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOn##_event##Listener)
 
 #define NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(_event)                      \
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOn##_event##Listener)
 
+#define NS_DISCONNECT_EVENT_HANDLER(_event)                                   \
+  if (mOn##_event##Listener) { mOn##_event##Listener->Disconnect(); }
+
 #define NS_UNMARK_LISTENER_WRAPPER(_event)                       \
   if (tmp->mOn##_event##Listener) {                              \
     nsCOMPtr<nsIXPConnectWrappedJS> wjs =                        \
       do_QueryInterface(tmp->mOn##_event##Listener->GetInner()); \
     xpc_UnmarkGrayObject(wjs);                                   \
   }
 
 #endif // nsDOMEventTargetHelper_h_
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -321,58 +321,20 @@ ok(e.type, "hello", "Wrong event type!")
 ok(!e.isTrusted, "Event shouldn't be trusted!");
 ok(e.bubbles, "Event should bubble!");
 ok(e.cancelable, "Event should be cancelable!");
 is(e.detail, 1, "detail should be 1");
 is(e.view, window, "view should be window");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
-// StorageEvent
+// UIEvent
 
 try {
-  e = new StorageEvent();
-} catch(exp) {
-  ex = true;
-}
-ok(ex, "First parameter is required!");
-ex = false;
-
-e = new StorageEvent("hello");
-ok(e.type, "hello", "Wrong event type!");
-ok(!e.isTrusted, "Event shouldn't be trusted!");
-ok(!e.bubbles, "Event shouldn't bubble!");
-ok(!e.cancelable, "Event shouldn't be cancelable!");
-is(e.key, "", "key should be ''");
-is(e.oldValue, null, "oldValue should be null");
-is(e.newValue, null, "newValue should be null");
-is(e.url, "", "url should be ''");
-document.dispatchEvent(e);
-is(receivedEvent, e, "Wrong event!");
-
-e = new StorageEvent("hello",
-  { bubbles: true, cancelable: true, key: "key",
-    oldValue: "oldValue", newValue: "newValue", url: "url",
-    storageArea: localStorage });
-ok(e.type, "hello", "Wrong event type!");
-ok(!e.isTrusted, "Event shouldn't be trusted!");
-ok(e.bubbles, "Event should bubble!");
-ok(e.cancelable, "Event should be cancelable!");
-is(e.key, "key", "Wrong value");
-is(e.oldValue, "oldValue", "Wrong value");
-is(e.newValue, "newValue", "Wrong value");
-is(e.url, "url", "Wrong value");
-is(e.storageArea, localStorage, "Wrong value");
-document.dispatchEvent(e);
-is(receivedEvent, e, "Wrong event!");
-
-// MouseEvent
-
-try {
-  e = new MouseEvent();
+  e = new UIEvent();
 } catch(exp) {
   ex = true;
 }
 ok(ex, "First parameter is required!");
 ex = false;
 
 e = new MouseEvent("hello");
 ok(e.type, "hello", "Wrong event type!");
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -17,21 +17,18 @@ using mozilla::dom::DOMRequest;
 using mozilla::dom::DOMRequestService;
 
 DOMRequest::DOMRequest(nsIDOMWindow* aWindow)
   : mDone(false)
   , mResult(JSVAL_VOID)
   , mRooted(false)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
-  mOwner = window->IsInnerWindow() ? window.get() :
-                                     window->GetCurrentInnerWindow();
-
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
-  mScriptContext = sgo->GetContext();
+  BindToOwner(window->IsInnerWindow() ? window.get() :
+                                        window->GetCurrentInnerWindow());
 }
 
 DOMCI_DATA(DOMRequest, DOMRequest)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
                                                   nsDOMEventTargetHelper)
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -917,47 +917,39 @@ NS_IMETHODIMP Navigator::GetMozNotificat
   *aRetVal = nsnull;
 
   if (mNotification) {
     NS_ADDREF(*aRetVal = mNotification);
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
-  nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(win));
-  NS_ENSURE_TRUE(sgo && win->GetDocShell(), NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(win && win->GetDocShell(), NS_ERROR_FAILURE);
 
-  nsIScriptContext* scx = sgo->GetContext();
-  NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
-
-  mNotification = new nsDesktopNotificationCenter(win, scx);
+  mNotification = new nsDesktopNotificationCenter(win);
 
   NS_ADDREF(*aRetVal = mNotification);
   return NS_OK;
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorBattery
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::GetMozBattery(nsIDOMMozBatteryManager** aBattery)
 {
   if (!mBatteryManager) {
     *aBattery = nsnull;
 
     nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
-    nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(win));
-    NS_ENSURE_TRUE(sgo && win->GetDocShell(), NS_OK);
-
-    nsIScriptContext* scx = sgo->GetContext();
-    NS_ENSURE_TRUE(scx, NS_OK);
+    NS_ENSURE_TRUE(win->GetDocShell(), NS_OK);
 
     mBatteryManager = new battery::BatteryManager();
-    mBatteryManager->Init(win, scx);
+    mBatteryManager->Init(win);
   }
 
   NS_ADDREF(*aBattery = mBatteryManager);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1078,24 +1070,18 @@ Navigator::GetMozSms(nsIDOMMozSmsManager
   if (!mSmsManager) {
     if (!IsSmsSupported() || !IsSmsAllowed()) {
       return NS_OK;
     }
 
     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
     NS_ENSURE_TRUE(window && window->GetDocShell(), NS_OK);
 
-    nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
-    NS_ENSURE_TRUE(sgo, NS_OK);
-
-    nsIScriptContext* scx = sgo->GetContext();
-    NS_ENSURE_TRUE(scx, NS_OK);
-
     mSmsManager = new sms::SmsManager();
-    mSmsManager->Init(window, scx);
+    mSmsManager->Init(window);
   }
 
   NS_ADDREF(*aSmsManager = mSmsManager);
 
   return NS_OK;
 }
 
 #ifdef MOZ_B2G_RIL
@@ -1134,24 +1120,18 @@ NS_IMETHODIMP
 Navigator::GetMozConnection(nsIDOMMozConnection** aConnection)
 {
   *aConnection = nsnull;
 
   if (!mConnection) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
     NS_ENSURE_TRUE(window && window->GetDocShell(), NS_OK);
 
-    nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
-    NS_ENSURE_TRUE(sgo, NS_OK);
-
-    nsIScriptContext* scx = sgo->GetContext();
-    NS_ENSURE_TRUE(scx, NS_OK);
-
     mConnection = new network::Connection();
-    mConnection->Init(window, scx);
+    mConnection->Init(window);
   }
 
   NS_ADDREF(*aConnection = mConnection);
   return NS_OK;
 }
 
 #ifdef MOZ_B2G_BT
 //*****************************************************************************
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1688,16 +1688,17 @@ struct nsConstructorFuncMapData
 #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func)                        \
   { eDOMClassInfo_##_class##_id, _func },
 
 #define NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(_class)   \
   { eDOMClassInfo_##_class##_id, NS_DOM##_class##Ctor },
 
 static const nsConstructorFuncMapData kConstructorFuncMap[] =
 {
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, nsDOMMultipartFile::NewBlob)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CustomEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PopStateEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(HashChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PageTransitionEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CloseEvent)
@@ -5687,16 +5688,148 @@ DefineInterfaceConstants(JSContext *cx, 
                              JSPROP_ENUMERATE)) {
       return NS_ERROR_UNEXPECTED;
     }
   }
 
   return NS_OK;
 }
 
+// This code is temporary until we remove support for the constants defined
+// on IDBCursor/IDBRequest/IDBTransaction
+
+struct IDBConstant
+{
+  const char* interface;
+  const char* name;
+  const char* value;
+  
+  static const char* IDBCursor;
+  static const char* IDBRequest;
+  static const char* IDBTransaction;
+};
+
+const char* IDBConstant::IDBCursor = "IDBCursor";
+const char* IDBConstant::IDBRequest = "IDBRequest";
+const char* IDBConstant::IDBTransaction = "IDBTransaction";
+
+static const IDBConstant sIDBConstants[] = {
+  { IDBConstant::IDBCursor,      "NEXT",              "next" },
+  { IDBConstant::IDBCursor,      "NEXT_NO_DUPLICATE", "nextunique" },
+  { IDBConstant::IDBCursor,      "PREV",              "prev" },
+  { IDBConstant::IDBCursor,      "PREV_NO_DUPLICATE", "prevunique" },
+  { IDBConstant::IDBRequest,     "LOADING",           "pending" },
+  { IDBConstant::IDBRequest,     "DONE",              "done" },
+  { IDBConstant::IDBTransaction, "READ_ONLY",         "readonly" },
+  { IDBConstant::IDBTransaction, "READ_WRITE",        "readwrite" },
+  { IDBConstant::IDBTransaction, "VERSION_CHANGE",    "versionchange" },
+};
+
+static JSBool
+IDBConstantGetter(JSContext *cx, JSObject *obj, jsid id, jsval* vp)
+{
+  MOZ_ASSERT(JSID_IS_INT(id));
+  
+  int8_t index = JSID_TO_INT(id);
+  
+  MOZ_ASSERT((uint8_t)index < mozilla::ArrayLength(sIDBConstants));
+
+  const IDBConstant& c = sIDBConstants[index];
+
+  // Put a warning on the console
+  nsString warnText =
+    NS_LITERAL_STRING("The constant ") +
+    NS_ConvertASCIItoUTF16(c.interface) +
+    NS_LITERAL_STRING(".") +
+    NS_ConvertASCIItoUTF16(c.name) +
+    NS_LITERAL_STRING(" has been deprecated. Use the string value \"") +
+    NS_ConvertASCIItoUTF16(c.value) +
+    NS_LITERAL_STRING("\" instead.");
+
+  PRUint64 windowID = 0;
+  nsIScriptContext* context = GetScriptContextFromJSContext(cx);
+  if (context) {
+    nsCOMPtr<nsPIDOMWindow> window =
+      do_QueryInterface(context->GetGlobalObject());
+    if (window) {
+      window = window->GetCurrentInnerWindow();
+    }
+    NS_WARN_IF_FALSE(window, "Missing a window, got a door?");
+    if (window) {
+      windowID = window->WindowID();
+    }
+  }
+
+  nsCOMPtr<nsIScriptError> errorObject =
+    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
+  NS_WARN_IF_FALSE(errorObject, "Failed to create error object");
+  if (errorObject) {
+    nsresult rv = errorObject->InitWithWindowID(warnText.get(),
+                                                nsnull, // file name
+                                                nsnull, // source line
+                                                0, 0, // Line/col number
+                                                nsIScriptError::warningFlag,
+                                                "DOM Core", windowID);
+    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to init error object");
+
+    if (NS_SUCCEEDED(rv)) {
+      nsCOMPtr<nsIConsoleService> consoleServ =
+        do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+      if (consoleServ) {
+        consoleServ->LogMessage(errorObject);
+      }
+    }
+  }
+
+  // Redefine property to remove getter
+  NS_ConvertASCIItoUTF16 valStr(c.value);
+  jsval value;
+  if (!xpc::StringToJsval(cx, valStr, &value)) {
+    return JS_FALSE;
+  }
+  if (!::JS_DefineProperty(cx, obj, c.name, value, nsnull, nsnull,
+                           JSPROP_ENUMERATE)) {
+    return JS_FALSE;
+  }
+
+  // Return value
+  *vp = value;
+  return JS_TRUE;
+}
+
+static nsresult
+DefineIDBInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
+{
+  const char* interface;
+  if (aIID->Equals(NS_GET_IID(nsIIDBCursor))) {
+    interface = IDBConstant::IDBCursor;
+  }
+  else if (aIID->Equals(NS_GET_IID(nsIIDBRequest))) {
+    interface = IDBConstant::IDBRequest;
+  }
+  else if (aIID->Equals(NS_GET_IID(nsIIDBTransaction))) {
+    interface = IDBConstant::IDBTransaction;
+  }
+
+  for (int8_t i = 0; i < (int8_t)mozilla::ArrayLength(sIDBConstants); ++i) {
+    const IDBConstant& c = sIDBConstants[i];
+    if (c.interface != interface) {
+      continue;
+    }
+
+    if (!::JS_DefinePropertyWithTinyId(cx, obj, c.name, i, JSVAL_VOID,
+                                       IDBConstantGetter, nsnull,
+                                       JSPROP_ENUMERATE)) {
+      return NS_ERROR_UNEXPECTED;
+    }
+  }
+
+  return NS_OK;
+}
+
 class nsDOMConstructor : public nsIDOMDOMConstructor
 {
 protected:
   nsDOMConstructor(const PRUnichar* aName,
                    bool aIsConstructable,
                    nsPIDOMWindow* aOwner)
     : mClassName(aName),
       mConstructable(aIsConstructable),
@@ -6093,16 +6226,25 @@ nsDOMConstructor::ResolveInterfaceConsta
   }
 
   // Special case for |IDBKeyRange| which gets funny "static" functions.
   if (class_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
       !indexedDB::IDBKeyRange::DefineConstructors(cx, obj)) {
     return NS_ERROR_FAILURE;
   }
 
+  // Special case a few IDB interfaces which for now are getting transitional
+  // constants.
+  if (class_iid->Equals(NS_GET_IID(nsIIDBCursor)) ||
+      class_iid->Equals(NS_GET_IID(nsIIDBRequest)) ||
+      class_iid->Equals(NS_GET_IID(nsIIDBTransaction))) {
+    rv = DefineIDBInterfaceConstants(cx, obj, class_iid);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMConstructor::ToString(nsAString &aResult)
 {
   aResult.AssignLiteral("[object ");
   aResult.Append(mClassName);
@@ -6236,16 +6378,25 @@ ResolvePrototype(nsIXPConnect *aXPConnec
     }
 
     // Special case for |IDBKeyRange| which gets funny "static" functions.
     if (primary_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
         !indexedDB::IDBKeyRange::DefineConstructors(cx, class_obj)) {
       return NS_ERROR_FAILURE;
     }
 
+    // Special case a few IDB interfaces which for now are getting transitional
+    // constants.
+    if (primary_iid->Equals(NS_GET_IID(nsIIDBCursor)) ||
+        primary_iid->Equals(NS_GET_IID(nsIIDBRequest)) ||
+        primary_iid->Equals(NS_GET_IID(nsIIDBTransaction))) {
+      rv = DefineIDBInterfaceConstants(cx, class_obj, primary_iid);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
     nsCOMPtr<nsIInterfaceInfoManager>
       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
     NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
 
     iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
     NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
 
     const nsIID *iid = nsnull;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -248,16 +248,17 @@
 #include "mozilla/dom/StructuredCloneTags.h"
 
 #include "nsRefreshDriver.h"
 #include "mozAutoDocUpdate.h"
 
 #include "mozilla/Telemetry.h"
 #include "nsLocation.h"
 #include "nsWrapperCacheInlines.h"
+#include "nsDOMEventTargetHelper.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gDOMLeakPRLog;
 #endif
@@ -962,16 +963,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
            ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
 #endif
 
   NS_ASSERTION(sWindowsById, "Windows hash table must be created!");
   NS_ASSERTION(!sWindowsById->Get(mWindowID),
                "This window shouldn't be in the hash table yet!");
   sWindowsById->Put(mWindowID, this);
+
+  mEventTargetObjects.Init();
 }
 
 /* static */
 void
 nsGlobalWindow::Init()
 {
   CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
   NS_ASSERTION(gEntropyCollector,
@@ -988,18 +991,30 @@ nsGlobalWindow::Init()
   // should happen.
 #ifdef DEBUG
   NS_ASSERTION(sWindowsById->Init(), "Init() should not fail!");
 #else
   sWindowsById->Init();
 #endif
 }
 
+static PLDHashOperator
+DisconnectEventTargetObjects(nsPtrHashKey<nsDOMEventTargetHelper>* aKey,
+                             void* aClosure)
+{
+  nsRefPtr<nsDOMEventTargetHelper> target = aKey->GetKey();
+  target->DisconnectFromOwner();
+  return PL_DHASH_NEXT;
+}
+
 nsGlobalWindow::~nsGlobalWindow()
 {
+  mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nsnull);
+  mEventTargetObjects.Clear();
+
   // We have to check if sWindowsById isn't null because ::Shutdown might have
   // been called.
   if (sWindowsById) {
     NS_ASSERTION(sWindowsById->Get(mWindowID),
                  "This window should be in the hash table");
     sWindowsById->Remove(mWindowID);
   }
 
@@ -1077,16 +1092,28 @@ nsGlobalWindow::~nsGlobalWindow()
   }
 
   DisableDeviceMotionUpdates();
   mHasDeviceMotion = false;
 
   nsLayoutStatics::Release();
 }
 
+void
+nsGlobalWindow::AddEventTargetObject(nsDOMEventTargetHelper* aObject)
+{
+  mEventTargetObjects.PutEntry(aObject);
+}
+
+void
+nsGlobalWindow::RemoveEventTargetObject(nsDOMEventTargetHelper* aObject)
+{
+  mEventTargetObjects.RemoveEntry(aObject);
+}
+
 // static
 void
 nsGlobalWindow::ShutDown()
 {
   if (gDumpFile && gDumpFile != stdout) {
     fclose(gDumpFile);
   }
   gDumpFile = nsnull;
@@ -1141,16 +1168,19 @@ nsGlobalWindow::CleanUp(bool aIgnoreModa
       return;
     }
   }
 
   // Guarantee idempotence.
   if (mCleanedUp)
     return;
   mCleanedUp = true;
+  
+  mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nsnull);
+  mEventTargetObjects.Clear();
 
   if (mObserver) {
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     if (os) {
       os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
       os->RemoveObserver(mObserver, "dom-storage2-changed");
       os->RemoveObserver(mObserver, "dom-storage-changed");
     }
@@ -3328,21 +3358,18 @@ nsGlobalWindow::GetApplicationCache(nsID
     nsCOMPtr<nsIURI> uri;
     nsresult rv = webNav->GetCurrentURI(getter_AddRefs(uri));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
     nsCOMPtr<nsIURI> manifestURI;
     nsContentUtils::GetOfflineAppManifest(doc, getter_AddRefs(manifestURI));
 
-    nsIScriptContext* scriptContext = GetContext();
-    NS_ENSURE_STATE(scriptContext);
-
     nsRefPtr<nsDOMOfflineResourceList> applicationCache =
-      new nsDOMOfflineResourceList(manifestURI, uri, this, scriptContext);
+      new nsDOMOfflineResourceList(manifestURI, uri, this);
     NS_ENSURE_TRUE(applicationCache, NS_ERROR_OUT_OF_MEMORY);
 
     applicationCache->Init();
 
     mApplicationCache = applicationCache;
   }
 
   NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -129,17 +129,17 @@ class nsHistory;
 class nsPerformance;
 class nsIDocShellLoadInfo;
 class WindowStateHolder;
 class nsGlobalWindowObserver;
 class nsGlobalWindow;
 class nsDummyJavaPluginOwner;
 class PostMessageEvent;
 class nsRunnable;
-
+class nsDOMEventTargetHelper;
 class nsDOMOfflineResourceList;
 class nsDOMMozURLProperty;
 
 #ifdef MOZ_DISABLE_DOMCRYPTO
 class nsIDOMCrypto;
 #endif
 
 class nsWindowSizes;
@@ -586,16 +586,19 @@ public:
 
   static WindowByIdTable* GetWindowsTable() {
     return sWindowsById;
   }
 
   void SizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;
 
   void UnmarkGrayTimers();
+
+  void AddEventTargetObject(nsDOMEventTargetHelper* aObject);
+  void RemoveEventTargetObject(nsDOMEventTargetHelper* aObject);
 private:
   // Enable updates for the accelerometer.
   void EnableDeviceMotionUpdates();
 
   // Disables updates for the accelerometer.
   void DisableDeviceMotionUpdates();
 
   // Implements Get{Real,Scriptable}Top.
@@ -1006,16 +1009,18 @@ protected:
   // checkbox is shown. In the case of ShowModalDialog another Confirm
   // dialog will be shown, the result of the checkbox/confirm dialog
   // will be stored in mDialogDisabled variable.
   TimeStamp                     mLastDialogQuitTime;
   bool                          mDialogDisabled;
 
   nsRefPtr<nsDOMMozURLProperty> mURLProperty;
 
+  nsTHashtable<nsPtrHashKey<nsDOMEventTargetHelper> > mEventTargetObjects;
+
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class PostMessageEvent;
 
   static WindowByIdTable* sWindowsById;
   static bool sWarnedAboutWindowInternal;
 };
 
--- a/dom/battery/BatteryManager.cpp
+++ b/dom/battery/BatteryManager.cpp
@@ -88,21 +88,19 @@ NS_IMPL_RELEASE_INHERITED(BatteryManager
 BatteryManager::BatteryManager()
   : mLevel(kDefaultLevel)
   , mCharging(kDefaultCharging)
   , mRemainingTime(kDefaultRemainingTime)
 {
 }
 
 void
-BatteryManager::Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext)
+BatteryManager::Init(nsPIDOMWindow *aWindow)
 {
-  // Those vars come from nsDOMEventTargetHelper.
-  mOwner = aWindow;
-  mScriptContext = aScriptContext;
+  BindToOwner(aWindow);
 
   hal::RegisterBatteryObserver(this);
 
   hal::BatteryInformation batteryInfo;
   hal::GetCurrentBatteryInformation(&batteryInfo);
 
   UpdateFromBatteryInfo(batteryInfo);
 }
--- a/dom/battery/BatteryManager.h
+++ b/dom/battery/BatteryManager.h
@@ -63,17 +63,17 @@ class BatteryManager : public nsDOMEvent
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZBATTERYMANAGER
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   BatteryManager();
 
-  void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
+  void Init(nsPIDOMWindow *aWindow);
   void Shutdown();
 
   // For IObserver.
   void Notify(const hal::BatteryInformation& aBatteryInfo);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BatteryManager,
                                            nsDOMEventTargetHelper)
 
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -152,17 +152,17 @@ private:
 
 END_INDEXEDDB_NAMESPACE
 
 // static
 already_AddRefed<IDBCursor>
 IDBCursor::Create(IDBRequest* aRequest,
                   IDBTransaction* aTransaction,
                   IDBObjectStore* aObjectStore,
-                  PRUint16 aDirection,
+                  Direction aDirection,
                   const Key& aRangeKey,
                   const nsACString& aContinueQuery,
                   const nsACString& aContinueToQuery,
                   const Key& aKey,
                   StructuredCloneReadInfo& aCloneReadInfo)
 {
   NS_ASSERTION(aObjectStore, "Null pointer!");
   NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
@@ -180,17 +180,17 @@ IDBCursor::Create(IDBRequest* aRequest,
   return cursor.forget();
 }
 
 // static
 already_AddRefed<IDBCursor>
 IDBCursor::Create(IDBRequest* aRequest,
                   IDBTransaction* aTransaction,
                   IDBIndex* aIndex,
-                  PRUint16 aDirection,
+                  Direction aDirection,
                   const Key& aRangeKey,
                   const nsACString& aContinueQuery,
                   const nsACString& aContinueToQuery,
                   const Key& aKey,
                   const Key& aObjectKey)
 {
   NS_ASSERTION(aIndex, "Null pointer!");
   NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
@@ -210,17 +210,17 @@ IDBCursor::Create(IDBRequest* aRequest,
   return cursor.forget();
 }
 
 // static
 already_AddRefed<IDBCursor>
 IDBCursor::Create(IDBRequest* aRequest,
                   IDBTransaction* aTransaction,
                   IDBIndex* aIndex,
-                  PRUint16 aDirection,
+                  Direction aDirection,
                   const Key& aRangeKey,
                   const nsACString& aContinueQuery,
                   const nsACString& aContinueToQuery,
                   const Key& aKey,
                   const Key& aObjectKey,
                   StructuredCloneReadInfo& aCloneReadInfo)
 {
   NS_ASSERTION(aIndex, "Null pointer!");
@@ -238,37 +238,58 @@ IDBCursor::Create(IDBRequest* aRequest,
   cursor->mKey = aKey;
   cursor->mObjectKey = aObjectKey;
   cursor->mCloneReadInfo.Swap(aCloneReadInfo);
 
   return cursor.forget();
 }
 
 // static
+nsresult
+IDBCursor::ParseDirection(const nsAString& aDirection, Direction* aResult)
+{
+  if (aDirection.EqualsLiteral("next")) {
+    *aResult = NEXT;
+  }
+  else if (aDirection.EqualsLiteral("nextunique")) {
+    *aResult = NEXT_UNIQUE;
+  }
+  else if (aDirection.EqualsLiteral("prev")) {
+    *aResult = PREV;
+  }
+  else if (aDirection.EqualsLiteral("prevunique")) {
+    *aResult = PREV_UNIQUE;
+  }
+  else {
+    return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
+  }
+  
+  return NS_OK;
+}
+
+// static
 already_AddRefed<IDBCursor>
 IDBCursor::CreateCommon(IDBRequest* aRequest,
                         IDBTransaction* aTransaction,
                         IDBObjectStore* aObjectStore,
-                        PRUint16 aDirection,
+                        Direction aDirection,
                         const Key& aRangeKey,
                         const nsACString& aContinueQuery,
                         const nsACString& aContinueToQuery)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aRequest, "Null pointer!");
   NS_ASSERTION(aTransaction, "Null pointer!");
   NS_ASSERTION(aObjectStore, "Null pointer!");
   NS_ASSERTION(!aContinueQuery.IsEmpty(), "Empty query!");
   NS_ASSERTION(!aContinueToQuery.IsEmpty(), "Empty query!");
 
   nsRefPtr<IDBCursor> cursor = new IDBCursor();
 
   IDBDatabase* database = aTransaction->Database();
-  cursor->mScriptContext = database->GetScriptContext();
-  cursor->mOwner = database->GetOwner();
   cursor->mScriptOwner = database->GetScriptOwner();
 
   if (cursor->mScriptOwner) {
     if (NS_FAILED(NS_HOLD_JS_OBJECTS(cursor, IDBCursor))) {
       return nsnull;
     }
 
     cursor->mRooted = true;
@@ -283,17 +304,17 @@ IDBCursor::CreateCommon(IDBRequest* aReq
   cursor->mRangeKey = aRangeKey;
 
   return cursor.forget();
 }
 
 IDBCursor::IDBCursor()
 : mScriptOwner(nsnull),
   mType(OBJECTSTORE),
-  mDirection(nsIIDBCursor::NEXT),
+  mDirection(IDBCursor::NEXT),
   mCachedKey(JSVAL_VOID),
   mCachedPrimaryKey(JSVAL_VOID),
   mCachedValue(JSVAL_VOID),
   mHaveCachedKey(false),
   mHaveCachedPrimaryKey(false),
   mHaveCachedValue(false),
   mRooted(false),
   mContinueCalled(false),
@@ -326,21 +347,21 @@ IDBCursor::ContinueInternal(const Key& a
   if (!mHaveValue || mContinueCalled) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   mContinueToKey = aKey;
 
 #ifdef DEBUG
   {
-    PRUint16 readyState;
-    if (NS_FAILED(mRequest->GetReadyState(&readyState))) {
+    nsAutoString readyState;
+    if (NS_FAILED(mRequest->GetReadyState(readyState))) {
       NS_ERROR("This should never fail!");
     }
-    NS_ASSERTION(readyState == nsIIDBRequest::DONE, "Should be DONE!");
+    NS_ASSERTION(readyState.EqualsLiteral("done"), "Should be DONE!");
   }
 #endif
 
   mRequest->Reset();
 
   nsRefPtr<ContinueHelper> helper;
   switch (mType) {
     case OBJECTSTORE:
@@ -371,18 +392,16 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRequest,
                                                        nsIDOMEventTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
                                                        nsIDOMEventTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObjectStore)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mIndex)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptContext)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
   NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
                "Should have a cached key");
   NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
                JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
                "Should have a cached primary key");
@@ -416,18 +435,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ID
     tmp->mCachedValue = JSVAL_VOID;
     tmp->mHaveCachedKey = false;
     tmp->mHaveCachedPrimaryKey = false;
     tmp->mHaveCachedValue = false;
     tmp->mRooted = false;
     tmp->mHaveValue = false;
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRequest)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptContext)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
   NS_INTERFACE_MAP_ENTRY(nsIIDBCursor)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIDBCursorWithValue, mType != INDEXKEY)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursorWithValue,
                                                    mType != INDEXKEY)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursor,
@@ -437,21 +454,34 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
 
 DOMCI_DATA(IDBCursor, IDBCursor)
 DOMCI_DATA(IDBCursorWithValue, IDBCursor)
 
 NS_IMETHODIMP
-IDBCursor::GetDirection(PRUint16* aDirection)
+IDBCursor::GetDirection(nsAString& aDirection)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  *aDirection = mDirection;
+  switch(mDirection) {
+    case NEXT:
+      aDirection.AssignLiteral("next");
+      break;
+    case NEXT_UNIQUE:
+      aDirection.AssignLiteral("nextunique");
+      break;
+    case PREV:
+      aDirection.AssignLiteral("prev");
+      break;
+    case PREV_UNIQUE:
+      aDirection.AssignLiteral("prevunique");
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBCursor::GetSource(nsISupports** aSource)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
@@ -563,25 +593,25 @@ IDBCursor::Continue(const jsval &aKey,
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   Key key;
   nsresult rv = key.SetFromJSVal(aCx, aKey);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!key.IsUnset()) {
     switch (mDirection) {
-      case nsIIDBCursor::NEXT:
-      case nsIIDBCursor::NEXT_NO_DUPLICATE:
+      case IDBCursor::NEXT:
+      case IDBCursor::NEXT_UNIQUE:
         if (key <= mKey) {
           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
         }
         break;
 
-      case nsIIDBCursor::PREV:
-      case nsIIDBCursor::PREV_NO_DUPLICATE:
+      case IDBCursor::PREV:
+      case IDBCursor::PREV_UNIQUE:
         if (key >= mKey) {
           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
         }
         break;
 
       default:
         NS_NOTREACHED("Unknown direction type!");
     }
@@ -854,18 +884,18 @@ ContinueIndexHelper::BindArgumentsToStat
   if (!mCursor->mRangeKey.IsUnset()) {
     NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
     rv = mCursor->mRangeKey.BindToStatement(aStatement, rangeKeyName);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Bind object key if duplicates are allowed and we're not continuing to a
   // specific key.
-  if ((mCursor->mDirection == nsIIDBCursor::NEXT ||
-       mCursor->mDirection == nsIIDBCursor::PREV) &&
+  if ((mCursor->mDirection == IDBCursor::NEXT ||
+       mCursor->mDirection == IDBCursor::PREV) &&
        mCursor->mContinueToKey.IsUnset()) {
     NS_ASSERTION(!mCursor->mObjectKey.IsUnset(), "Bad key!");
 
     NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
     rv = mCursor->mObjectKey.BindToStatement(aStatement, objectKeyName);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -72,97 +72,106 @@ class IDBCursor : public nsIIDBCursorWit
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBCURSOR
   NS_DECL_NSIIDBCURSORWITHVALUE
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBCursor)
 
+  enum Type
+  {
+    OBJECTSTORE = 0,
+    INDEXKEY,
+    INDEXOBJECT
+  };
+
+  enum Direction
+  {
+    NEXT = 0,
+    NEXT_UNIQUE,
+    PREV,
+    PREV_UNIQUE
+  };
+
   // For OBJECTSTORE cursors.
   static
   already_AddRefed<IDBCursor>
   Create(IDBRequest* aRequest,
          IDBTransaction* aTransaction,
          IDBObjectStore* aObjectStore,
-         PRUint16 aDirection,
+         Direction aDirection,
          const Key& aRangeKey,
          const nsACString& aContinueQuery,
          const nsACString& aContinueToQuery,
          const Key& aKey,
          StructuredCloneReadInfo& aCloneReadInfo);
 
   // For INDEXKEY cursors.
   static
   already_AddRefed<IDBCursor>
   Create(IDBRequest* aRequest,
          IDBTransaction* aTransaction,
          IDBIndex* aIndex,
-         PRUint16 aDirection,
+         Direction aDirection,
          const Key& aRangeKey,
          const nsACString& aContinueQuery,
          const nsACString& aContinueToQuery,
          const Key& aKey,
          const Key& aObjectKey);
 
   // For INDEXOBJECT cursors.
   static
   already_AddRefed<IDBCursor>
   Create(IDBRequest* aRequest,
          IDBTransaction* aTransaction,
          IDBIndex* aIndex,
-         PRUint16 aDirection,
+         Direction aDirection,
          const Key& aRangeKey,
          const nsACString& aContinueQuery,
          const nsACString& aContinueToQuery,
          const Key& aKey,
          const Key& aObjectKey,
          StructuredCloneReadInfo& aCloneReadInfo);
 
-  enum Type
-  {
-    OBJECTSTORE = 0,
-    INDEXKEY,
-    INDEXOBJECT
-  };
-
   IDBTransaction* Transaction()
   {
     return mTransaction;
   }
 
+  static nsresult ParseDirection(const nsAString& aDirection,
+                                 Direction* aResult);
+
 protected:
   IDBCursor();
   ~IDBCursor();
 
   static
   already_AddRefed<IDBCursor>
   CreateCommon(IDBRequest* aRequest,
                IDBTransaction* aTransaction,
                IDBObjectStore* aObjectStore,
-               PRUint16 aDirection,
+               Direction aDirection,
                const Key& aRangeKey,
                const nsACString& aContinueQuery,
                const nsACString& aContinueToQuery);
 
   nsresult
   ContinueInternal(const Key& aKey,
                    PRInt32 aCount);
 
   nsRefPtr<IDBRequest> mRequest;
   nsRefPtr<IDBTransaction> mTransaction;
   nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBIndex> mIndex;
 
-  nsCOMPtr<nsIScriptContext> mScriptContext;
-  nsCOMPtr<nsPIDOMWindow> mOwner;
   JSObject* mScriptOwner;
 
   Type mType;
-  PRUint16 mDirection;
+  Direction mDirection;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
 
   // These are cycle-collected!
   jsval mCachedKey;
   jsval mCachedPrimaryKey;
   jsval mCachedValue;
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -157,18 +157,17 @@ IDBDatabase::Create(IDBWrapperCache* aOw
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
 
   nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
   NS_ASSERTION(databaseInfo, "Null pointer!");
 
   nsRefPtr<IDBDatabase> db(new IDBDatabase());
 
-  db->mScriptContext = aOwnerCache->GetScriptContext();
-  db->mOwner = aOwnerCache->GetOwner();
+  db->BindToOwner(aOwnerCache);
   if (!db->SetScriptOwner(aOwnerCache->GetScriptOwner())) {
     return nsnull;
   }
 
   db->mDatabaseId = databaseInfo->id;
   db->mName = databaseInfo->name;
   db->mFilePath = databaseInfo->filePath;
   databaseInfo.swap(db->mDatabaseInfo);
@@ -382,17 +381,17 @@ IDBDatabase::CreateObjectStore(const nsA
                                JSContext* aCx,
                                nsIIDBObjectStore** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
-      transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
+      transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   DatabaseInfo* databaseInfo = transaction->DBInfo();
 
   mozilla::dom::IDBObjectStoreParameters params;
   nsString keyPath;
   keyPath.SetIsVoid(true);
@@ -502,17 +501,17 @@ IDBDatabase::CreateObjectStore(const nsA
 NS_IMETHODIMP
 IDBDatabase::DeleteObjectStore(const nsAString& aName)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
-      transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
+      transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   DatabaseInfo* info = transaction->DBInfo();
   ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName);
   if (!objectStoreInfo) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
@@ -524,17 +523,17 @@ IDBDatabase::DeleteObjectStore(const nsA
 
   transaction->RemoveObjectStore(aName);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::Transaction(const jsval& aStoreNames,
-                         PRUint16 aMode,
+                         const nsAString& aMode,
                          JSContext* aCx,
                          PRUint8 aOptionalArgCount,
                          nsIIDBTransaction** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (IndexedDatabaseManager::IsShuttingDown()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -543,25 +542,25 @@ IDBDatabase::Transaction(const jsval& aS
   if (mClosed) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   if (mRunningVersionChange) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
+  IDBTransaction::Mode transactionMode = IDBTransaction::READ_ONLY;
   if (aOptionalArgCount) {
-    if (aMode != nsIIDBTransaction::READ_WRITE &&
-        aMode != nsIIDBTransaction::READ_ONLY) {
+    if (aMode.EqualsLiteral("readwrite")) {
+      transactionMode = IDBTransaction::READ_WRITE;
+    }
+    else if (!aMode.EqualsLiteral("readonly")) {
       return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
     }
   }
-  else {
-    aMode = nsIIDBTransaction::READ_ONLY;
-  }
 
   nsresult rv;
   nsTArray<nsString> storesToOpen;
 
   if (!JSVAL_IS_PRIMITIVE(aStoreNames)) {
     JSObject* obj = JSVAL_TO_OBJECT(aStoreNames);
 
     // See if this is a JS array.
@@ -653,17 +652,17 @@ IDBDatabase::Transaction(const jsval& aS
   DatabaseInfo* info = Info();
   for (PRUint32 index = 0; index < storesToOpen.Length(); index++) {
     if (!info->ContainsStoreName(storesToOpen[index])) {
       return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
     }
   }
 
   nsRefPtr<IDBTransaction> transaction =
-    IDBTransaction::Create(this, storesToOpen, aMode, false);
+    IDBTransaction::Create(this, storesToOpen, transactionMode, false);
   NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   transaction.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::Close()
@@ -676,31 +675,31 @@ IDBDatabase::Close()
   return NS_OK;
 }
 
 nsresult
 IDBDatabase::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
 
-  if (!mOwner) {
+  if (!GetOwner()) {
     return NS_OK;
   }
 
   if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
     nsString type;
     nsresult rv = aVisitor.mDOMEvent->GetType(type);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (type.EqualsLiteral(ERROR_EVT_STR)) {
       nsRefPtr<nsDOMEvent> duplicateEvent =
         CreateGenericEvent(type, eDoesNotBubble, eNotCancelable);
       NS_ENSURE_STATE(duplicateEvent);
 
-      nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mOwner));
+      nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(GetOwner()));
       NS_ASSERTION(target, "How can this happen?!");
 
       bool dummy;
       rv = target->DispatchEvent(duplicateEvent, &dummy);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -98,21 +98,22 @@ public:
 
   const nsString& FilePath()
   {
     return mFilePath;
   }
 
   already_AddRefed<nsIDocument> GetOwnerDocument()
   {
-    if (!mOwner) {
+    if (!GetOwner()) {
       return nsnull;
     }
 
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(mOwner->GetExtantDocument());
+    nsCOMPtr<nsIDocument> doc =
+      do_QueryInterface(GetOwner()->GetExtantDocument());
     return doc.forget();
   }
 
   nsCString& Origin()
   {
     return mASCIIOrigin;
   }
 
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -463,39 +463,32 @@ IDBFactory::OpenCommon(const nsAString& 
     // we do not end up in a side thread that asks for the path (which
     // would make ContentChild try to send a message in a thread other
     // than the main one).
     ContentChild::GetSingleton()->GetIndexedDBPath();
   }
 
   nsCOMPtr<nsPIDOMWindow> window;
   nsCOMPtr<nsIScriptGlobalObject> sgo;
-  nsIScriptContext* context = nsnull;
   JSObject* scriptOwner = nsnull;
 
   if (mWindow) {
-    sgo = do_QueryInterface(mWindow);
-    NS_ENSURE_TRUE(sgo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    context = sgo->GetContext();
-    NS_ENSURE_TRUE(context, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
     window = mWindow;
   }
   else {
     scriptOwner = mOwningObject;
   }
 
   nsCString origin;
   nsresult rv =
     IndexedDatabaseManager::GetASCIIOriginFromWindow(window, origin);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<IDBOpenDBRequest> request =
-    IDBOpenDBRequest::Create(context, window, scriptOwner);
+    IDBOpenDBRequest::Create(window, scriptOwner);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenDatabaseHelper> openHelper =
     new OpenDatabaseHelper(request, aName, origin, aVersion, aDeleting);
 
   rv = openHelper->Init();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -181,17 +181,17 @@ protected:
 
 class OpenKeyCursorHelper : public AsyncConnectionHelper
 {
 public:
   OpenKeyCursorHelper(IDBTransaction* aTransaction,
                       IDBRequest* aRequest,
                       IDBIndex* aIndex,
                       IDBKeyRange* aKeyRange,
-                      PRUint16 aDirection)
+                      IDBCursor::Direction aDirection)
   : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
     mKeyRange(aKeyRange), mDirection(aDirection)
   { }
 
   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
   nsresult GetSuccessResult(JSContext* aCx,
                             jsval* aVal);
 
@@ -201,34 +201,34 @@ public:
     mKeyRange = nsnull;
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
   nsRefPtr<IDBKeyRange> mKeyRange;
-  const PRUint16 mDirection;
+  const IDBCursor::Direction mDirection;
 
   // Out-params.
   Key mKey;
   Key mObjectKey;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
 };
 
 class OpenCursorHelper : public AsyncConnectionHelper
 {
 public:
   OpenCursorHelper(IDBTransaction* aTransaction,
                    IDBRequest* aRequest,
                    IDBIndex* aIndex,
                    IDBKeyRange* aKeyRange,
-                   PRUint16 aDirection)
+                   IDBCursor::Direction aDirection)
   : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
     mKeyRange(aKeyRange), mDirection(aDirection)
   { }
 
   ~OpenCursorHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
   }
@@ -243,17 +243,17 @@ public:
     mKeyRange = nsnull;
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
   nsRefPtr<IDBKeyRange> mKeyRange;
-  const PRUint16 mDirection;
+  const IDBCursor::Direction mDirection;
 
   // Out-params.
   Key mKey;
   Key mObjectKey;
   StructuredCloneReadInfo mCloneReadInfo;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
@@ -577,100 +577,90 @@ IDBIndex::GetAllKeys(const jsval& aKey,
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::OpenCursor(const jsval& aKey,
-                     PRUint16 aDirection,
+                     const nsAString& aDirection,
                      JSContext* aCx,
                      PRUint8 aOptionalArgCount,
                      nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   nsresult rv;
 
+  IDBCursor::Direction direction = IDBCursor::NEXT;
+
   nsRefPtr<IDBKeyRange> keyRange;
   if (aOptionalArgCount) {
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aOptionalArgCount >= 2) {
-      if (aDirection != nsIIDBCursor::NEXT &&
-          aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
-          aDirection != nsIIDBCursor::PREV &&
-          aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
-        return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
-      }
-    }
-    else {
-      aDirection = nsIIDBCursor::NEXT;
+      rv = IDBCursor::ParseDirection(aDirection, &direction);
+      NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenCursorHelper> helper =
-    new OpenCursorHelper(transaction, request, this, keyRange, aDirection);
+    new OpenCursorHelper(transaction, request, this, keyRange, direction);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBIndex::OpenKeyCursor(const jsval& aKey,
-                        PRUint16 aDirection,
+                        const nsAString& aDirection,
                         JSContext* aCx,
                         PRUint8 aOptionalArgCount,
                         nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = mObjectStore->Transaction();
   if (!transaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   nsresult rv;
 
+  IDBCursor::Direction direction = IDBCursor::NEXT;
+
   nsRefPtr<IDBKeyRange> keyRange;
   if (aOptionalArgCount) {
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aOptionalArgCount >= 2) {
-      if (aDirection != nsIIDBCursor::NEXT &&
-          aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
-          aDirection != nsIIDBCursor::PREV &&
-          aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
-        return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
-      }
-    }
-    else {
-      aDirection = nsIIDBCursor::NEXT;
+      rv = IDBCursor::ParseDirection(aDirection, &direction);
+      NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenKeyCursorHelper> helper =
-    new OpenKeyCursorHelper(transaction, request, this, keyRange, aDirection);
+    new OpenKeyCursorHelper(transaction, request, this, keyRange, direction);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
@@ -1027,26 +1017,26 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(value, keyRangeClause);
   }
 
   nsCAutoString directionClause(" ORDER BY value ");
   switch (mDirection) {
-    case nsIIDBCursor::NEXT:
-    case nsIIDBCursor::NEXT_NO_DUPLICATE:
+    case IDBCursor::NEXT:
+    case IDBCursor::NEXT_UNIQUE:
       directionClause += NS_LITERAL_CSTRING("ASC, object_data_key ASC");
       break;
 
-    case nsIIDBCursor::PREV:
+    case IDBCursor::PREV:
       directionClause += NS_LITERAL_CSTRING("DESC, object_data_key DESC");
       break;
 
-    case nsIIDBCursor::PREV_NO_DUPLICATE:
+    case IDBCursor::PREV_UNIQUE:
       directionClause += NS_LITERAL_CSTRING("DESC, object_data_key ASC");
       break;
 
     default:
       NS_NOTREACHED("Unknown direction!");
   }
   nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, object_data_key "
                                             "FROM ") + table +
@@ -1087,17 +1077,17 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
   // Now we need to make the query to get the next match.
   nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT value, object_data_key"
                                                 " FROM ") + table +
                              NS_LITERAL_CSTRING(" WHERE index_id = :id");
 
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
 
   switch (mDirection) {
-    case nsIIDBCursor::NEXT:
+    case IDBCursor::NEXT:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
       mContinueQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND value >= :current_key AND "
@@ -1107,33 +1097,33 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
         NS_LITERAL_CSTRING(" LIMIT ");
       mContinueToQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND value >= :current_key ") +
         directionClause +
         NS_LITERAL_CSTRING(" LIMIT ");
       break;
 
-    case nsIIDBCursor::NEXT_NO_DUPLICATE:
+    case IDBCursor::NEXT_UNIQUE:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
       mContinueQuery =
         queryStart + NS_LITERAL_CSTRING(" AND value > :current_key") +
         directionClause +
         NS_LITERAL_CSTRING(" LIMIT ");
       mContinueToQuery =
         queryStart + NS_LITERAL_CSTRING(" AND value >= :current_key") +
         directionClause +
         NS_LITERAL_CSTRING(" LIMIT ");
       break;
 
-    case nsIIDBCursor::PREV:
+    case IDBCursor::PREV:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
 
       mContinueQuery =
         queryStart +
@@ -1144,17 +1134,17 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
         NS_LITERAL_CSTRING(" LIMIT ");
       mContinueToQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND value <= :current_key ") +
         directionClause +
         NS_LITERAL_CSTRING(" LIMIT ");
       break;
 
-    case nsIIDBCursor::PREV_NO_DUPLICATE:
+    case IDBCursor::PREV_UNIQUE:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
       mContinueQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND value < :current_key") +
@@ -1208,28 +1198,28 @@ OpenCursorHelper::DoDatabaseWork(mozISto
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(value, keyRangeClause);
   }
 
   nsCAutoString directionClause(" ORDER BY index_table.value ");
   switch (mDirection) {
-    case nsIIDBCursor::NEXT:
-    case nsIIDBCursor::NEXT_NO_DUPLICATE:
+    case IDBCursor::NEXT:
+    case IDBCursor::NEXT_UNIQUE:
       directionClause +=
         NS_LITERAL_CSTRING("ASC, index_table.object_data_key ASC");
       break;
 
-    case nsIIDBCursor::PREV:
+    case IDBCursor::PREV:
       directionClause +=
         NS_LITERAL_CSTRING("DESC, index_table.object_data_key DESC");
       break;
 
-    case nsIIDBCursor::PREV_NO_DUPLICATE:
+    case IDBCursor::PREV_UNIQUE:
       directionClause +=
         NS_LITERAL_CSTRING("DESC, index_table.object_data_key ASC");
       break;
 
     default:
       NS_NOTREACHED("Unknown direction!");
   }
 
@@ -1287,17 +1277,17 @@ OpenCursorHelper::DoDatabaseWork(mozISto
                        "index_table.object_data_id = object_data.id "
                        "WHERE index_table.index_id = :id");
 
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
 
   NS_NAMED_LITERAL_CSTRING(limit, " LIMIT ");
 
   switch (mDirection) {
-    case nsIIDBCursor::NEXT:
+    case IDBCursor::NEXT:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
       mContinueQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND index_table.value >= :current_key AND "
@@ -1305,33 +1295,33 @@ OpenCursorHelper::DoDatabaseWork(mozISto
                            "  index_table.object_data_key > :object_key ) ") +
         directionClause + limit;
       mContinueToQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
         directionClause + limit;
       break;
 
-    case nsIIDBCursor::NEXT_NO_DUPLICATE:
+    case IDBCursor::NEXT_UNIQUE:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
       mContinueQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND index_table.value > :current_key") +
         directionClause + limit;
       mContinueToQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
         directionClause + limit;
       break;
 
-    case nsIIDBCursor::PREV:
+    case IDBCursor::PREV:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
       mContinueQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND index_table.value <= :current_key AND "
@@ -1339,17 +1329,17 @@ OpenCursorHelper::DoDatabaseWork(mozISto
                            "  index_table.object_data_key < :object_key ) ") +
         directionClause + limit;
       mContinueToQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") +
         directionClause + limit;
       break;
 
-    case nsIIDBCursor::PREV_NO_DUPLICATE:
+    case IDBCursor::PREV_UNIQUE:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
       mContinueQuery =
         queryStart +
         NS_LITERAL_CSTRING(" AND index_table.value < :current_key") +
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -193,17 +193,17 @@ protected:
 
 class OpenCursorHelper : public AsyncConnectionHelper
 {
 public:
   OpenCursorHelper(IDBTransaction* aTransaction,
                    IDBRequest* aRequest,
                    IDBObjectStore* aObjectStore,
                    IDBKeyRange* aKeyRange,
-                   PRUint16 aDirection)
+                   IDBCursor::Direction aDirection)
   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
     mKeyRange(aKeyRange), mDirection(aDirection)
   { }
 
   ~OpenCursorHelper()
   {
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
   }
@@ -219,17 +219,17 @@ public:
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneReadInfo.mCloneBuffer);
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   // In-params.
   nsRefPtr<IDBObjectStore> mObjectStore;
   nsRefPtr<IDBKeyRange> mKeyRange;
-  const PRUint16 mDirection;
+  const IDBCursor::Direction mDirection;
 
   // Out-params.
   Key mKey;
   StructuredCloneReadInfo mCloneReadInfo;
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
 };
@@ -1632,52 +1632,47 @@ IDBObjectStore::Clear(nsIIDBRequest** _r
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::OpenCursor(const jsval& aKey,
-                           PRUint16 aDirection,
+                           const nsAString& aDirection,
                            JSContext* aCx,
                            PRUint8 aOptionalArgCount,
                            nsIIDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   nsresult rv;
 
+  IDBCursor::Direction direction = IDBCursor::NEXT;
+
   nsRefPtr<IDBKeyRange> keyRange;
   if (aOptionalArgCount) {
     rv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aOptionalArgCount >= 2) {
-      if (aDirection != nsIIDBCursor::NEXT &&
-          aDirection != nsIIDBCursor::NEXT_NO_DUPLICATE &&
-          aDirection != nsIIDBCursor::PREV &&
-          aDirection != nsIIDBCursor::PREV_NO_DUPLICATE) {
-        return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
-      }
-    }
-    else {
-      aDirection = nsIIDBCursor::NEXT;
+      rv = IDBCursor::ParseDirection(aDirection, &direction);
+      NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenCursorHelper> helper =
-    new OpenCursorHelper(mTransaction, request, this, keyRange, aDirection);
+    new OpenCursorHelper(mTransaction, request, this, keyRange, direction);
 
   rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
 
@@ -1745,17 +1740,17 @@ IDBObjectStore::CreateIndex(const nsAStr
     keyPath = str;
   }
 
   // Check name and current mode
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
       transaction != mTransaction ||
-      mTransaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
+      mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   bool found = false;
   PRUint32 indexCount = mInfo->indexes.Length();
   for (PRUint32 index = 0; index < indexCount; index++) {
     if (mInfo->indexes[index].name == aName) {
       found = true;
@@ -1871,17 +1866,17 @@ NS_IMETHODIMP
 IDBObjectStore::DeleteIndex(const nsAString& aName)
 {
   NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
       transaction != mTransaction ||
-      mTransaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
+      mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
 
   PRUint32 index = 0;
   for (; index < mInfo->indexes.Length(); index++) {
     if (mInfo->indexes[index].name == aName) {
@@ -2280,23 +2275,23 @@ OpenCursorHelper::DoDatabaseWork(mozISto
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(keyValue, keyRangeClause);
   }
 
   nsCAutoString directionClause;
   switch (mDirection) {
-    case nsIIDBCursor::NEXT:
-    case nsIIDBCursor::NEXT_NO_DUPLICATE:
+    case IDBCursor::NEXT:
+    case IDBCursor::NEXT_UNIQUE:
       directionClause.AssignLiteral(" ORDER BY key_value ASC");
       break;
 
-    case nsIIDBCursor::PREV:
-    case nsIIDBCursor::PREV_NO_DUPLICATE:
+    case IDBCursor::PREV:
+    case IDBCursor::PREV_UNIQUE:
       directionClause.AssignLiteral(" ORDER BY key_value DESC");
       break;
 
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
   nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids "
@@ -2339,34 +2334,34 @@ OpenCursorHelper::DoDatabaseWork(mozISto
   // Now we need to make the query to get the next match.
   keyRangeClause.Truncate();
   nsCAutoString continueToKeyRangeClause;
 
   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
 
   switch (mDirection) {
-    case nsIIDBCursor::NEXT:
-    case nsIIDBCursor::NEXT_NO_DUPLICATE:
+    case IDBCursor::NEXT:
+    case IDBCursor::NEXT_UNIQUE:
       AppendConditionClause(keyValue, currentKey, false, false,
                             keyRangeClause);
       AppendConditionClause(keyValue, currentKey, false, true,
                             continueToKeyRangeClause);
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(keyValue, rangeKey, true,
                               !mKeyRange->IsUpperOpen(), keyRangeClause);
         AppendConditionClause(keyValue, rangeKey, true,
                               !mKeyRange->IsUpperOpen(),
                               continueToKeyRangeClause);
         mRangeKey = mKeyRange->Upper();
       }
       break;
 
-    case nsIIDBCursor::PREV:
-    case nsIIDBCursor::PREV_NO_DUPLICATE:
+    case IDBCursor::PREV:
+    case IDBCursor::PREV_UNIQUE:
       AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause);
       AppendConditionClause(keyValue, currentKey, true, true,
                            continueToKeyRangeClause);
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(keyValue, rangeKey, false,
                               !mKeyRange->IsLowerOpen(), keyRangeClause);
         AppendConditionClause(keyValue, rangeKey, false,
                               !mKeyRange->IsLowerOpen(),
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -81,18 +81,17 @@ IDBRequest::Create(nsISupports* aSource,
                    IDBWrapperCache* aOwnerCache,
                    IDBTransaction* aTransaction)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBRequest> request(new IDBRequest());
 
   request->mSource = aSource;
   request->mTransaction = aTransaction;
-  request->mScriptContext = aOwnerCache->GetScriptContext();
-  request->mOwner = aOwnerCache->GetOwner();
+  request->BindToOwner(aOwnerCache);
   if (!request->SetScriptOwner(aOwnerCache->GetScriptOwner())) {
     return nsnull;
   }
 
   return request.forget();
 }
 
 void
@@ -138,17 +137,19 @@ IDBRequest::NotifyHelperCompleted(Helper
     if (NS_FAILED(cxStack->GetSafeJSContext(&cx))) {
       NS_WARNING("Failed to get safe JSContext!");
       rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       mErrorCode = NS_ERROR_GET_CODE(rv);
       return rv;
     }
   }
   else {
-    cx = mScriptContext->GetNativeContext();
+    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+    NS_ENSURE_STATE(sc);
+    cx = sc->GetNativeContext();
     NS_ASSERTION(cx, "Failed to get a context!");
   } 
 
   JSObject* global = GetParentObject();
   NS_ASSERTION(global, "This should never be null!");
 
   JSAutoRequest ar(cx);
   JSAutoEnterCompartment ac;
@@ -184,23 +185,26 @@ IDBRequest::RootResultValInternal()
 
 void
 IDBRequest::UnrootResultValInternal()
 {
   NS_DROP_JS_OBJECTS(this, IDBRequest);
 }
 
 NS_IMETHODIMP
-IDBRequest::GetReadyState(PRUint16* aReadyState)
+IDBRequest::GetReadyState(nsAString& aReadyState)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  *aReadyState = mHaveResultOrErrorCode ?
-                 nsIIDBRequest::DONE :
-                 nsIIDBRequest::LOADING;
+  if (mHaveResultOrErrorCode) {
+    aReadyState.AssignLiteral("done");
+  }
+  else {
+    aReadyState.AssignLiteral("pending");
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBRequest::GetSource(nsISupports** aSource)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -305,25 +309,23 @@ IDBOpenDBRequest::~IDBOpenDBRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   UnrootResultVal();
 }
 
 // static
 already_AddRefed<IDBOpenDBRequest>
-IDBOpenDBRequest::Create(nsIScriptContext* aScriptContext,
-                         nsPIDOMWindow* aOwner,
+IDBOpenDBRequest::Create(nsPIDOMWindow* aOwner,
                          JSObject* aScriptOwner)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBOpenDBRequest> request(new IDBOpenDBRequest());
 
-  request->mScriptContext = aScriptContext;
-  request->mOwner = aOwner;
+  request->BindToOwner(aOwner);
   if (!request->SetScriptOwner(aScriptOwner)) {
     return nsnull;
   }
 
   return request.forget();
 }
 
 void
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -132,25 +132,24 @@ class IDBOpenDBRequest : public IDBReque
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIIDBREQUEST(IDBRequest::)
   NS_DECL_NSIIDBOPENDBREQUEST
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest, IDBRequest)
 
   static
   already_AddRefed<IDBOpenDBRequest>
-  Create(nsIScriptContext* aScriptContext,
-         nsPIDOMWindow* aOwner,
+  Create(nsPIDOMWindow* aOwner,
          JSObject* aScriptOwner);
 
   static
   already_AddRefed<IDBOpenDBRequest>
   Create(IDBWrapperCache* aOwnerCache)
   {
-    return Create(aOwnerCache->GetScriptContext(), aOwnerCache->GetOwner(),
+    return Create(aOwnerCache->GetOwner(),
                   aOwnerCache->GetScriptOwner());
   }
 
   void SetTransaction(IDBTransaction* aTransaction);
 
 protected:
   ~IDBOpenDBRequest();
 
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -105,25 +105,24 @@ NS_IMPL_QUERY_INTERFACE1(StartTransactio
 StartTransactionRunnable gStartTransactionRunnable;
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBTransaction>
 IDBTransaction::Create(IDBDatabase* aDatabase,
                        nsTArray<nsString>& aObjectStoreNames,
-                       PRUint16 aMode,
+                       Mode aMode,
                        bool aDispatchDelayed)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<IDBTransaction> transaction = new IDBTransaction();
 
-  transaction->mScriptContext = aDatabase->GetScriptContext();
-  transaction->mOwner = aDatabase->GetOwner();
+  transaction->BindToOwner(aDatabase);
   if (!transaction->SetScriptOwner(aDatabase->GetScriptOwner())) {
     return nsnull;
   }
 
   transaction->mDatabase = aDatabase;
   transaction->mMode = aMode;
   
   transaction->mDatabaseInfo = aDatabase->Info();
@@ -152,27 +151,27 @@ IDBTransaction::Create(IDBDatabase* aDat
     transaction->mCreatedRecursionDepth = depth - 1;
 
     rv = thread->AddObserver(transaction);
     NS_ENSURE_SUCCESS(rv, nsnull);
 
     transaction->mCreating = true;
   }
 
-  if (aMode != nsIIDBTransaction::VERSION_CHANGE) {
+  if (aMode != IDBTransaction::VERSION_CHANGE) {
     TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
     pool->Dispatch(transaction, &gStartTransactionRunnable, false, nsnull);
   }
 
   return transaction.forget();
 }
 
 IDBTransaction::IDBTransaction()
-: mReadyState(nsIIDBTransaction::INITIAL),
-  mMode(nsIIDBTransaction::READ_ONLY),
+: mReadyState(IDBTransaction::INITIAL),
+  mMode(IDBTransaction::READ_ONLY),
   mPendingRequests(0),
   mCreatedRecursionDepth(0),
   mSavepointCount(0),
   mAborted(false),
   mCreating(false)
 #ifdef DEBUG
   , mFiredCompleteOrAbort(false)
 #endif
@@ -192,41 +191,41 @@ IDBTransaction::~IDBTransaction()
   nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this), this);
 }
 
 void
 IDBTransaction::OnNewRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   if (!mPendingRequests) {
-    NS_ASSERTION(mReadyState == nsIIDBTransaction::INITIAL,
+    NS_ASSERTION(mReadyState == IDBTransaction::INITIAL,
                  "Reusing a transaction!");
-    mReadyState = nsIIDBTransaction::LOADING;
+    mReadyState = IDBTransaction::LOADING;
   }
   ++mPendingRequests;
 }
 
 void
 IDBTransaction::OnRequestFinished()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mPendingRequests, "Mismatched calls!");
   --mPendingRequests;
   if (!mPendingRequests) {
-    NS_ASSERTION(mAborted || mReadyState == nsIIDBTransaction::LOADING,
+    NS_ASSERTION(mAborted || mReadyState == IDBTransaction::LOADING,
                  "Bad state!");
     mReadyState = IDBTransaction::COMMITTING;
     CommitOrRollback();
   }
 }
 
 void
 IDBTransaction::RemoveObjectStore(const nsAString& aName)
 {
-  NS_ASSERTION(mMode == nsIIDBTransaction::VERSION_CHANGE,
+  NS_ASSERTION(mMode == IDBTransaction::VERSION_CHANGE,
                "Only remove object stores on VERSION_CHANGE transactions");
 
   mDatabaseInfo->RemoveObjectStore(aName);
 
   for (PRUint32 i = 0; i < mCreatedObjectStores.Length(); i++) {
     if (mCreatedObjectStores[i]->Name() == aName) {
       mCreatedObjectStores.RemoveElementAt(i);
       break;
@@ -339,17 +338,17 @@ IDBTransaction::GetOrCreateConnection(mo
     nsCOMPtr<mozIStorageConnection> connection =
       IDBFactory::GetConnection(mDatabase->FilePath());
     NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
 
     nsresult rv;
 
     nsRefPtr<UpdateRefcountFunction> function;
     nsCString beginTransaction;
-    if (mMode != nsIIDBTransaction::READ_ONLY) {
+    if (mMode != IDBTransaction::READ_ONLY) {
       function = new UpdateRefcountFunction(Database()->Manager());
       NS_ENSURE_TRUE(function, NS_ERROR_OUT_OF_MEMORY);
 
       rv = function->Init();
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = connection->CreateFunction(
         NS_LITERAL_CSTRING("update_refcount"), 2, function);
@@ -412,28 +411,28 @@ IDBTransaction::GetCachedStatement(const
 }
 
 bool
 IDBTransaction::IsOpen() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   // If we haven't started anything then we're open.
-  if (mReadyState == nsIIDBTransaction::INITIAL) {
+  if (mReadyState == IDBTransaction::INITIAL) {
     NS_ASSERTION(AsyncConnectionHelper::GetCurrentTransaction() != this,
                  "This should be some other transaction (or null)!");
     return true;
   }
 
   // If we've already started then we need to check to see if we still have the
   // mCreating flag set. If we do (i.e. we haven't returned to the event loop
   // from the time we were created) then we are open. Otherwise check the
   // currently running transaction to see if it's the same. We only allow other
   // requests to be made if this transaction is currently running.
-  if (mReadyState == nsIIDBTransaction::LOADING) {
+  if (mReadyState == IDBTransaction::LOADING) {
     if (mCreating) {
       return true;
     }
 
     if (AsyncConnectionHelper::GetCurrentTransaction() == this) {
       return true;
     }
   }
@@ -524,30 +523,31 @@ IDBTransaction::GetDb(nsIIDBDatabase** a
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ADDREF(*aDB = mDatabase);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBTransaction::GetReadyState(PRUint16* aReadyState)
+IDBTransaction::GetMode(nsAString& aMode)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  *aReadyState = mReadyState;
-  return NS_OK;
-}
+  switch(mMode) {
+    case READ_ONLY:
+      aMode.AssignLiteral("readonly");
+      break;
+    case READ_WRITE:
+      aMode.AssignLiteral("readwrite");
+      break;
+    case VERSION_CHANGE:
+      aMode.AssignLiteral("versionchange");
+  }
 
-NS_IMETHODIMP
-IDBTransaction::GetMode(PRUint16* aMode)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  *aMode = mMode;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBTransaction::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
@@ -582,17 +582,17 @@ IDBTransaction::ObjectStore(const nsAStr
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   ObjectStoreInfo* info = nsnull;
 
-  if (mMode == nsIIDBTransaction::VERSION_CHANGE ||
+  if (mMode == IDBTransaction::VERSION_CHANGE ||
       mObjectStoreNames.Contains(aName)) {
     info = mDatabaseInfo->GetObjectStore(aName);
   }
 
   if (!info) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
@@ -610,22 +610,22 @@ IDBTransaction::Abort()
 
   // We can't use IsOpen here since we need it to be possible to call Abort()
   // even from outside of transaction callbacks.
   if (mReadyState != IDBTransaction::INITIAL &&
       mReadyState != IDBTransaction::LOADING) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
-  bool needToCommitOrRollback = mReadyState == nsIIDBTransaction::INITIAL;
+  bool needToCommitOrRollback = mReadyState == IDBTransaction::INITIAL;
 
   mAborted = true;
-  mReadyState = nsIIDBTransaction::DONE;
+  mReadyState = IDBTransaction::DONE;
 
-  if (Mode() == nsIIDBTransaction::VERSION_CHANGE) {
+  if (Mode() == IDBTransaction::VERSION_CHANGE) {
     // If a version change transaction is aborted, the db must be closed
     mDatabase->Close();
   }
 
   // Fire the abort event if there are no outstanding requests. Otherwise the
   // abort event will be fired when all outstanding requests finish.
   if (needToCommitOrRollback) {
     return CommitOrRollback();
@@ -672,18 +672,18 @@ IDBTransaction::AfterProcessNextEvent(ns
                "Should be impossible!");
   NS_ASSERTION(mCreating, "Should be true!");
 
   if (aRecursionDepth == mCreatedRecursionDepth) {
     // We're back at the event loop, no longer newborn.
     mCreating = false;
 
     // Maybe set the readyState to DONE if there were no requests generated.
-    if (mReadyState == nsIIDBTransaction::INITIAL) {
-      mReadyState = nsIIDBTransaction::DONE;
+    if (mReadyState == IDBTransaction::INITIAL) {
+      mReadyState = IDBTransaction::DONE;
 
       if (NS_FAILED(CommitOrRollback())) {
         NS_WARNING("Failed to commit!");
       }
     }
 
     // No longer need to observe thread events.
     if(NS_FAILED(aThread->RemoveObserver(this))) {
@@ -720,29 +720,29 @@ CommitHelper::~CommitHelper()
 NS_IMPL_THREADSAFE_ISUPPORTS1(CommitHelper, nsIRunnable)
 
 NS_IMETHODIMP
 CommitHelper::Run()
 {
   if (NS_IsMainThread()) {
     NS_ASSERTION(mDoomedObjects.IsEmpty(), "Didn't release doomed objects!");
 
-    mTransaction->mReadyState = nsIIDBTransaction::DONE;
+    mTransaction->mReadyState = IDBTransaction::DONE;
 
     // Release file infos on the main thread, so they will eventually get
     // destroyed on correct thread.
     mTransaction->ClearCreatedFileInfos();
     if (mUpdateFileRefcountFunction) {
       mUpdateFileRefcountFunction->ClearFileInfoEntries();
       mUpdateFileRefcountFunction = nsnull;
     }
 
     nsCOMPtr<nsIDOMEvent> event;
     if (mAborted) {
-      if (mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE) {
+      if (mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE) {
         // This will make the database take a snapshot of it's DatabaseInfo
         mTransaction->Database()->Close();
         // Then remove the info from the hash as it contains invalid data.
         DatabaseInfo::Remove(mTransaction->Database()->Id());
       }
 
       event = CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR),
                                  eDoesBubble, eNotCancelable);
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -88,20 +88,35 @@ class IDBTransaction : public IDBWrapper
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIIDBTRANSACTION
   NS_DECL_NSITHREADOBSERVER
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, IDBWrapperCache)
 
+  enum Mode
+  {
+    READ_ONLY = 0,
+    READ_WRITE,
+    VERSION_CHANGE
+  };
+
+  enum ReadyState
+  {
+    INITIAL = 0,
+    LOADING,
+    COMMITTING,
+    DONE
+  };
+
   static already_AddRefed<IDBTransaction>
   Create(IDBDatabase* aDatabase,
          nsTArray<nsString>& aObjectStoreNames,
-         PRUint16 aMode,
+         Mode aMode,
          bool aDispatchDelayed);
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   void OnNewRequest();
   void OnRequestFinished();
 
@@ -125,26 +140,26 @@ public:
   {
     return GetCachedStatement(NS_LITERAL_CSTRING(aQuery));
   }
 
   bool IsOpen() const;
 
   bool IsWriteAllowed() const
   {
-    return mMode == nsIIDBTransaction::READ_WRITE ||
-           mMode == nsIIDBTransaction::VERSION_CHANGE;
+    return mMode == READ_WRITE || mMode == VERSION_CHANGE;
   }
 
   bool IsAborted() const
   {
     return mAborted;
   }
 
-  PRUint16 Mode()
+  // 'Get' prefix is to avoid name collisions with the enum
+  Mode GetMode()
   {
     return mMode;
   }
 
   IDBDatabase* Database()
   {
     NS_ASSERTION(mDatabase, "This should never be null!");
     return mDatabase;
@@ -167,18 +182,18 @@ private:
   IDBTransaction();
   ~IDBTransaction();
 
   nsresult CommitOrRollback();
 
   nsRefPtr<IDBDatabase> mDatabase;
   nsRefPtr<DatabaseInfo> mDatabaseInfo;
   nsTArray<nsString> mObjectStoreNames;
-  PRUint16 mReadyState;
-  PRUint16 mMode;
+  ReadyState mReadyState;
+  Mode mMode;
   PRUint32 mPendingRequests;
   PRUint32 mCreatedRecursionDepth;
 
   // Only touched on the main thread.
   NS_DECL_EVENT_HANDLER(error)
   NS_DECL_EVENT_HANDLER(complete)
   NS_DECL_EVENT_HANDLER(abort)
 
--- a/dom/indexedDB/IDBWrapperCache.h
+++ b/dom/indexedDB/IDBWrapperCache.h
@@ -22,26 +22,16 @@ public:
                                                    nsDOMEventTargetHelper)
 
   JSObject* GetScriptOwner() const
   {
     return mScriptOwner;
   }
   bool SetScriptOwner(JSObject* aScriptOwner);
 
-  nsIScriptContext* GetScriptContext() const
-  {
-    return mScriptContext;
-  }
-
-  nsPIDOMWindow* GetOwner() const
-  {
-    return mOwner;
-  }
-
   JSObject* GetParentObject()
   {
     if (mScriptOwner) {
       return mScriptOwner;
     }
 
     // Do what nsEventTargetSH::PreCreate does.
     nsCOMPtr<nsIScriptGlobalObject> parent;
--- a/dom/indexedDB/TransactionThreadPool.cpp
+++ b/dom/indexedDB/TransactionThreadPool.cpp
@@ -270,24 +270,24 @@ TransactionThreadPool::FinishTransaction
         count--;
 
         continue;
       }
 
       const nsTArray<nsString>& objectStores = transaction->mObjectStoreNames;
 
       bool dummy;
-      if (transaction->mMode == nsIIDBTransaction::READ_WRITE) {
+      if (transaction->mMode == IDBTransaction::READ_WRITE) {
         if (NS_FAILED(CheckOverlapAndMergeObjectStores(storesWriting,
                                                        objectStores,
                                                        true, &dummy))) {
           NS_WARNING("Out of memory!");
         }
       }
-      else if (transaction->mMode == nsIIDBTransaction::READ_ONLY) {
+      else if (transaction->mMode == IDBTransaction::READ_ONLY) {
         if (NS_FAILED(CheckOverlapAndMergeObjectStores(storesReading,
                                                        objectStores,
                                                        true, &dummy))) {
           NS_WARNING("Out of memory!");
         }
       }
       else {
         NS_NOTREACHED("Unknown mode!");
@@ -353,29 +353,29 @@ TransactionThreadPool::TransactionCanRun
   }
 
   NS_ASSERTION(mode != IDBTransaction::VERSION_CHANGE, "How did we get here?");
 
   bool writeOverlap;
   nsresult rv =
     CheckOverlapAndMergeObjectStores(dbTransactionInfo->storesWriting,
                                      objectStoreNames,
-                                     mode == nsIIDBTransaction::READ_WRITE,
+                                     mode == IDBTransaction::READ_WRITE,
                                      &writeOverlap);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool readOverlap;
   rv = CheckOverlapAndMergeObjectStores(dbTransactionInfo->storesReading,
                                         objectStoreNames,
-                                        mode == nsIIDBTransaction::READ_ONLY,
+                                        mode == IDBTransaction::READ_ONLY,
                                         &readOverlap);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (writeOverlap ||
-      (readOverlap && mode == nsIIDBTransaction::READ_WRITE)) {
+      (readOverlap && mode == IDBTransaction::READ_WRITE)) {
     *aCanRun = false;
     *aExistingQueue = nsnull;
     return NS_OK;
   }
 
   *aCanRun = true;
   *aExistingQueue = nsnull;
   return NS_OK;
@@ -436,17 +436,17 @@ TransactionThreadPool::Dispatch(IDBTrans
     // Make a new struct for this transaction.
     autoDBTransactionInfo = new DatabaseTransactionInfo();
     dbTransactionInfo = autoDBTransactionInfo;
   }
 
   const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
 
   nsTArray<nsString>& storesInUse =
-    aTransaction->mMode == nsIIDBTransaction::READ_WRITE ?
+    aTransaction->mMode == IDBTransaction::READ_WRITE ?
     dbTransactionInfo->storesWriting :
     dbTransactionInfo->storesReading;
 
   if (!storesInUse.AppendElements(objectStoreNames)) {
     NS_WARNING("Out of memory!");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
--- a/dom/indexedDB/nsIIDBCursor.idl
+++ b/dom/indexedDB/nsIIDBCursor.idl
@@ -41,24 +41,21 @@
 
 interface nsIIDBRequest;
 
 /**
  * IDBCursor interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBCursor for more
  * information.
  */
-[scriptable, builtinclass, uuid(9d5ddd43-132d-418e-81e8-17d64a6467a2)]
+[scriptable, builtinclass, uuid(01136b3a-d84c-487c-b929-f5d012346c44)]
 interface nsIIDBCursor : nsISupports
 {
-  const unsigned short NEXT = 0;
-  const unsigned short NEXT_NO_DUPLICATE = 1;
-  const unsigned short PREV = 2;
-  const unsigned short PREV_NO_DUPLICATE = 3;
-  readonly attribute unsigned short direction;
+  // "next", "nextunique", "prev" or "prevunique"
+  readonly attribute DOMString direction;
 
   readonly attribute nsISupports source;
 
   [implicit_jscontext]
   readonly attribute jsval key;
 
   [implicit_jscontext]
   readonly attribute jsval primaryKey;
--- a/dom/indexedDB/nsIIDBDatabase.idl
+++ b/dom/indexedDB/nsIIDBDatabase.idl
@@ -40,29 +40,28 @@
 #include "nsISupports.idl"
 
 interface nsIIDBObjectStore;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 interface nsIDOMEventListener;
 
-[scriptable, uuid(fb143548-08d1-43b4-95f2-a1cd58f8db76)]
-interface nsIIDBObjectStoreParameters : nsISupports
+dictionary IDBObjectStoreParameters
 {
-  attribute jsval keyPath;
-  attribute boolean autoIncrement;
+  jsval keyPath;
+  boolean autoIncrement;
 };
 
 /**
  * IDBDatabase interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
  * for more information.
  */
-[scriptable, builtinclass, uuid(bb877dff-ab5b-4ebb-9b3c-a7fa97cd4b51)]
+[scriptable, builtinclass, uuid(bedee48a-f47f-44f2-ba1e-d8fe595bbfee)]
 interface nsIIDBDatabase : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute unsigned long long version;
 
   readonly attribute nsIDOMDOMStringList objectStoreNames;
 
@@ -70,20 +69,21 @@ interface nsIIDBDatabase : nsISupports
   nsIIDBObjectStore
   createObjectStore([Null(Stringify)] in DOMString name,
                     /* nsIIDBObjectStoreParameters */
                     [optional /* none */] in jsval options);
 
   void
   deleteObjectStore([Null(Stringify)] in DOMString name);
 
+  // mode can be either "readonly" or "readwrite"
   [optional_argc, implicit_jscontext]
   nsIIDBTransaction
   transaction(in jsval storeNames, // js array of strings
-              [optional /* READ_ONLY */] in unsigned short mode);
+              [optional /* "readonly" */] in DOMString mode);
 
   void
   close();
 
   attribute nsIDOMEventListener onabort;
 
   attribute nsIDOMEventListener onerror;
 
--- a/dom/indexedDB/nsIIDBIndex.idl
+++ b/dom/indexedDB/nsIIDBIndex.idl
@@ -42,17 +42,17 @@
 interface nsIIDBObjectStore;
 interface nsIIDBRequest;
 
 /**
  * IDBIndex interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBIndex for more
  * information.
  */
-[scriptable, builtinclass, uuid(233ec586-7b34-4263-b27e-a4991b757597)]
+[scriptable, builtinclass, uuid(a859747a-0f05-4dfb-8f42-05c61415d4e4)]
 interface nsIIDBIndex : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute DOMString storeName;
 
   [implicit_jscontext]
   readonly attribute jsval keyPath;
@@ -76,23 +76,25 @@ interface nsIIDBIndex : nsISupports
   getAll([optional /* null */] in jsval key,
          [optional /* unlimited */] in unsigned long limit);
 
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
   getAllKeys([optional /* null */] in jsval key,
              [optional /* unlimited */] in unsigned long limit);
 
+  // direction can be "next", "nextunique", "prev" or "prevunique"
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
   openCursor([optional /* null */] in jsval key,
-             [optional /* nsIIDBCursor::NEXT */] in unsigned short direction);
+             [optional /* "next" */] in DOMString direction);
 
+  // direction can be "next", "nextunique", "prev" or "prevunique"
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
   openKeyCursor([optional /* null */] in jsval key,
-                [optional /* nsIIDBCursor::NEXT */] in unsigned short direction);
+                [optional /* "next" */] in DOMString direction);
 
   // Accepts null, a key value, or a nsIIDBKeyRange object.
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
   count([optional] in jsval key);
 };
--- a/dom/indexedDB/nsIIDBObjectStore.idl
+++ b/dom/indexedDB/nsIIDBObjectStore.idl
@@ -40,29 +40,28 @@
 #include "nsISupports.idl"
 
 interface nsIIDBIndex;
 interface nsIIDBKeyRange;
 interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 
-[scriptable, uuid(450e02fd-a87a-47d4-beaf-321417dad781)]
-interface nsIIDBIndexParameters : nsISupports
+dictionary IDBIndexParameters
 {
-  attribute boolean unique;
-  attribute boolean multiEntry;
+  boolean unique;
+  boolean multiEntry;
 };
 
 /**
  * nsIIDBObjectStore interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore
  * for more information.
  */
-[scriptable, builtinclass, uuid(e0d308ea-b804-4962-918a-28ec0aa4e42b)]
+[scriptable, builtinclass, uuid(43157a3c-bed1-4ce7-98c0-11365b852560)]
 interface nsIIDBObjectStore : nsISupports
 {
   readonly attribute DOMString name;
 
   [implicit_jscontext]
   readonly attribute jsval keyPath;
 
   readonly attribute nsIDOMDOMStringList indexNames;
@@ -100,20 +99,21 @@ interface nsIIDBObjectStore : nsISupport
   delete(in jsval key);
 
   // Success fires IDBTransactionEvent, result == null
   nsIIDBRequest
   clear();
 
   // Success fires IDBTransactionEvent, result == IDBCursor or result == null if
   // no match.
+  // direction can be "next", "nextunique", "prev" or "prevunique"
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
   openCursor([optional /* null */] in jsval range,
-             [optional /* NEXT */] in unsigned short direction);
+             [optional /* "next" */] in DOMString direction);
 
   [implicit_jscontext]
   nsIIDBIndex
   createIndex([Null(Stringify)] in DOMString name,
               in jsval keyPath,
               /* nsIIDBIndexParameters */
               [optional /* none */] in jsval options);
 
--- a/dom/indexedDB/nsIIDBRequest.idl
+++ b/dom/indexedDB/nsIIDBRequest.idl
@@ -43,22 +43,21 @@
 interface nsIDOMEventListener;
 interface nsIIDBTransaction;
 
 /**
  * IDBReqeust interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more
  * information.
  */
-[scriptable, builtinclass, uuid(a1e4a0ff-e0b2-431c-89cf-43b078189e27)]
+[scriptable, builtinclass, uuid(fe30ca60-bb90-4d68-af2f-4735f9228a54)]
 interface nsIIDBRequest : nsISupports
 {
-  const unsigned short LOADING = 1;
-  const unsigned short DONE = 2;
-  readonly attribute unsigned short readyState;
+  // "pending" or "done"
+  readonly attribute DOMString readyState;
 
   readonly attribute nsISupports source;
 
   readonly attribute nsIIDBTransaction transaction;
 
   readonly attribute jsval result;
 
   readonly attribute unsigned short errorCode;
--- a/dom/indexedDB/nsIIDBTransaction.idl
+++ b/dom/indexedDB/nsIIDBTransaction.idl
@@ -45,31 +45,23 @@ interface nsIIDBRequest;
 interface nsIIDBDatabase;
 interface nsIDOMDOMStringList;
 
 /**
  * IDBDTransaction interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBTransaction
  * for more information.
  */
-[scriptable, builtinclass, uuid(4f25832d-de40-4c0b-a176-358d94384b19)]
+[scriptable, builtinclass, uuid(e4927c76-4f1f-4d7d-80ad-8186e1677da6)]
 interface nsIIDBTransaction : nsISupports
 {
   readonly attribute nsIIDBDatabase db;
 
-  const unsigned short INITIAL = 0;
-  const unsigned short LOADING = 1;
-  const unsigned short COMMITTING = 2;
-  const unsigned short DONE = 3;
-  readonly attribute unsigned short readyState;
-
-  const unsigned short READ_ONLY = 0;
-  const unsigned short READ_WRITE = 1;
-  const unsigned short VERSION_CHANGE = 2;
-  readonly attribute unsigned short mode;
+  // "readonly", "readwrite" or "versionchange"
+  readonly attribute DOMString mode;
 
   readonly attribute nsIDOMDOMStringList objectStoreNames;
 
   nsIIDBObjectStore
   objectStore([Null(Stringify)] in DOMString name);
 
   // Don't commit the transaction.
   void abort();
--- a/dom/indexedDB/test/browser_quotaPrompt.html
+++ b/dom/indexedDB/test/browser_quotaPrompt.html
@@ -2,23 +2,21 @@
   Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/
 -->
 <html>
   <head>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
-      const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-
       let db;
       let version = window.location.href.charAt(window.location.href.length - 1);
 
       function onAddMore() {
-        let transaction = db.transaction("foo", READ_WRITE);
+        let transaction = db.transaction("foo", "readwrite");
 
         transaction.oncomplete = function(event) {
           setTimeout(testFinishedCallback, 0, "complete");
         }
         transaction.onabort = function(event) {
           setTimeout(testFinishedCallback, 0, "abort");
         }
 
--- a/dom/indexedDB/test/browser_quotaPromptDatabases.html
+++ b/dom/indexedDB/test/browser_quotaPromptDatabases.html
@@ -2,18 +2,16 @@
   Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/
 -->
 <html>
   <head>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
-      const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-
       let db;
       let i = 0;
 
       function onAddMore() {
         const name = window.location.pathname + i++;
 
         let request = mozIndexedDB.open(name, 1);
         request.onerror = errorHandler;
--- a/dom/indexedDB/test/browser_quotaPromptDelete.html
+++ b/dom/indexedDB/test/browser_quotaPromptDelete.html
@@ -2,23 +2,21 @@
   Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/
 -->
 <html>
   <head>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
-      const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-
       let db;
       let name = window.location.pathname;
 
       function onAddMore() {
-        let transaction = db.transaction("foo", READ_WRITE);
+        let transaction = db.transaction("foo", "readwrite");
 
         transaction.oncomplete = function(event) {
           setTimeout(testFinishedCallback, 0, "complete");
         }
         transaction.onabort = function(event) {
           setTimeout(testFinishedCallback, 0, "abort");
         }
 
--- a/dom/indexedDB/test/test_create_objectStore.html
+++ b/dom/indexedDB/test/test_create_objectStore.html
@@ -7,19 +7,16 @@
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
-      const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
-      const nsIIDBTransaction = Components.interfaces.nsIIDBTransaction;
-
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreInfo = [
         { name: "1", options: { keyPath: null } },
         { name: "2", options: { keyPath: null, autoIncrement: true } },
         { name: "3", options: { keyPath: null, autoIncrement: false } },
         { name: "4", options: { keyPath: null } },
         { name: "5", options: { keyPath: "foo" } },
@@ -95,19 +92,17 @@
         is(objectStore.name, name, "Bad name");
         is(objectStore.keyPath, info.options && info.options.keyPath ?
                                 info.options.keyPath : null,
            "Bad keyPath");
         if(objectStore.indexNames.length, 0, "Bad indexNames");
 
         ok(event.target.transaction, "event has a transaction");
         ok(event.target.transaction.db === db, "transaction has the right db");
-        is(event.target.transaction.readyState, nsIIDBTransaction.LOADING,
-           "transaction has the correct readyState");
-        is(event.target.transaction.mode, nsIIDBTransaction.VERSION_CHANGE,
+        is(event.target.transaction.mode, "versionchange",
            "transaction has the correct mode");
         is(event.target.transaction.objectStoreNames.length, index + 1,
            "transaction has correct objectStoreNames list");
         found = false;
         for (let j = 0; j < event.target.transaction.objectStoreNames.length;
              j++) {
           if (event.target.transaction.objectStoreNames.item(j) == name) {
             found = true;
--- a/dom/indexedDB/test/test_deleteDatabase.html
+++ b/dom/indexedDB/test/test_deleteDatabase.html
@@ -8,19 +8,16 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
 
   function testSteps()
   {
-    const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-    const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
-
     const name = window.location.pathname;
 
     ok(mozIndexedDB.deleteDatabase, "deleteDatabase function should exist!");
 
     let request = mozIndexedDB.open(name, 10);
     request.onerror = errorHandler;
     request.onsuccess = unexpectedSuccessHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
--- a/dom/indexedDB/test/test_deleteDatabase_interactions.html
+++ b/dom/indexedDB/test/test_deleteDatabase_interactions.html
@@ -8,19 +8,16 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
 
   function testSteps()
   {
-    const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-    const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
-
     const name = window.location.pathname;
 
     let request = mozIndexedDB.open(name, 10);
     request.onerror = errorHandler;
     request.onsuccess = unexpectedSuccessHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
 
     ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
--- a/dom/indexedDB/test/test_readonly_transactions.html
+++ b/dom/indexedDB/test/test_readonly_transactions.html
@@ -7,19 +7,16 @@
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
-      const READ_ONLY = Components.interfaces.nsIIDBTransaction.READ_ONLY;
-      const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-
       const name = window.location.pathname;
       const description = "My Test Database";
       const osName = "foo";
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
@@ -29,92 +26,92 @@
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
       db.createObjectStore(osName, { autoIncrement: "true" });
 
       yield;
 
       let key1, key2;
 
-      request = db.transaction([osName], READ_WRITE)
+      request = db.transaction([osName], "readwrite")
                   .objectStore(osName)
                   .add({});
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         key1 = event.target.result;
         testGenerator.next();
       }
       yield;
 
-      request = db.transaction(osName, READ_WRITE).objectStore(osName).add({});
+      request = db.transaction(osName, "readwrite").objectStore(osName).add({});
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         key2 = event.target.result;
         testGenerator.next();
       }
       yield;
 
-      request = db.transaction([osName], READ_WRITE)
+      request = db.transaction([osName], "readwrite")
                   .objectStore(osName)
                   .put({}, key1);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         testGenerator.next();
       }
       yield;
 
-      request = db.transaction(osName, READ_WRITE)
+      request = db.transaction(osName, "readwrite")
                   .objectStore(osName)
                   .put({}, key2);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         testGenerator.next();
       }
       yield;
 
-      request = db.transaction([osName], READ_WRITE)
+      request = db.transaction([osName], "readwrite")
                   .objectStore(osName)
                   .put({}, key1);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         testGenerator.next();
       }
       yield;
 
-      request = db.transaction(osName, READ_WRITE)
+      request = db.transaction(osName, "readwrite")
                   .objectStore(osName)
                   .put({}, key1);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         testGenerator.next();
       }
       yield;
 
-      request = db.transaction([osName], READ_WRITE)
+      request = db.transaction([osName], "readwrite")
                   .objectStore(osName)
                   .delete(key1);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         testGenerator.next();
       }
       yield;
 
-      request = db.transaction(osName, READ_WRITE)
+      request = db.transaction(osName, "readwrite")
                   .objectStore(osName)
                   .delete(key2);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(event.target.transaction.mode, READ_WRITE, "Correct mode");
+        is(event.target.transaction.mode, "readwrite", "Correct mode");
         testGenerator.next();
       }
       yield;
 
       try {
         request = db.transaction([osName]).objectStore(osName).add({});
         ok(false, "Adding to a readonly transaction should fail!");
       }
--- a/dom/indexedDB/test/unit/test_advance.js
+++ b/dom/indexedDB/test/unit/test_advance.js
@@ -139,17 +139,17 @@ function testSteps()
     }
   };
   yield;
 
   is(count, 0, "Saw all data");
 
   count = dataCount - 1;
 
-  getObjectStore().openCursor(null, IDBCursor.PREV).onsuccess = function(event) {
+  getObjectStore().openCursor(null, "prev").onsuccess = function(event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.primaryKey, count, "Got correct object");
       count--;
       if (count == dataCount - 2) {
         cursor.advance(10);
         count -= 9;
       }
@@ -162,17 +162,17 @@ function testSteps()
     }
   };
   yield;
 
   is(count, -1, "Saw all data");
 
   count = dataCount - 1;
 
-  getObjectStore().openCursor(null, IDBCursor.PREV).onsuccess = function(event) {
+  getObjectStore().openCursor(null, "prev").onsuccess = function(event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.primaryKey, count, "Got correct object");
       if (count == dataCount - 1) {
         cursor.advance(dataCount + 1);
       }
       else {
         ok(false, "Should never get here!");
--- a/dom/indexedDB/test/unit/test_clear.js
+++ b/dom/indexedDB/test/unit/test_clear.js
@@ -2,18 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
   const entryCount = 1000;
 
   let request = mozIndexedDB.open(name, 1, description);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
@@ -59,17 +57,17 @@ function testSteps()
   try {
     db.transaction("foo").objectStore("foo").clear();
     ok(false, "clear should throw on READ_ONLY transactions");
   }
   catch (e) {
     ok(true, "clear should throw on READ_ONLY transactions");
   }
 
-  request = db.transaction("foo", READ_WRITE).objectStore("foo").clear();
+  request = db.transaction("foo", "readwrite").objectStore("foo").clear();
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   ok(event.target.result === undefined, "Correct event.target.result");
   ok(request.result === undefined, "Correct request.result");
   ok(request === event.target, "Correct event.target");
 
@@ -79,17 +77,17 @@ function testSteps()
     let cursor = request.result;
     if (cursor) {
       ok(false, "Shouldn't have any entries");
     }
     continueToNextStep();
   }
   yield;
 
-  request = db.transaction("foo", READ_WRITE).objectStore("foo").add({});
+  request = db.transaction("foo", "readwrite").objectStore("foo").add({});
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   isnot(event.target.result, firstKey, "Got a different key");
 
   finishTest();
   yield;
--- a/dom/indexedDB/test/unit/test_create_index.js
+++ b/dom/indexedDB/test/unit/test_create_index.js
@@ -2,19 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
-  const nsIIDBTransaction = Components.interfaces.nsIIDBTransaction;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
   const objectStoreInfo = [
     { name: "a", options: { keyPath: "id", autoIncrement: true } },
     { name: "b", options: { keyPath: "id", autoIncrement: false } },
   ];
   const indexInfo = [
     { name: "1", keyPath: "unique_value", options: { unique: true } },
@@ -104,19 +101,17 @@ function testSteps()
           break;
         }
       }
       ok(found, "Name is on objectStore.indexNames");
 
       ok(event.target.transaction, "event has a transaction");
       ok(event.target.transaction.db === db,
          "transaction has the right db");
-      is(event.target.transaction.readyState, nsIIDBTransaction.LOADING,
-         "transaction has the correct readyState");
-      is(event.target.transaction.mode, nsIIDBTransaction.VERSION_CHANGE,
+      is(event.target.transaction.mode, "versionchange",
          "transaction has the correct mode");
       is(event.target.transaction.objectStoreNames.length, i + 1,
          "transaction only has one object store");
       is(event.target.transaction.objectStoreNames.item(0), objectStoreName,
          "transaction has the correct object store");
     }
   }
 
--- a/dom/indexedDB/test/unit/test_create_objectStore.js
+++ b/dom/indexedDB/test/unit/test_create_objectStore.js
@@ -2,19 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
-  const nsIIDBTransaction = Components.interfaces.nsIIDBTransaction;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
   const objectStoreInfo = [
     { name: "1", options: { keyPath: null } },
     { name: "2", options: { keyPath: null, autoIncrement: true } },
     { name: "3", options: { keyPath: null, autoIncrement: false } },
     { name: "4", options: { keyPath: null } },
     { name: "5", options: { keyPath: "foo" } },
@@ -82,19 +79,17 @@ function testSteps()
     is(objectStore.name, name, "Bad name");
     is(objectStore.keyPath, info.options && info.options.keyPath ?
                             info.options.keyPath : null,
        "Bad keyPath");
     if(objectStore.indexNames.length, 0, "Bad indexNames");
 
     ok(event.target.transaction, "event has a transaction");
     ok(event.target.transaction.db === db, "transaction has the right db");
-    is(event.target.transaction.readyState, nsIIDBTransaction.LOADING,
-       "transaction has the correct readyState");
-    is(event.target.transaction.mode, nsIIDBTransaction.VERSION_CHANGE,
+    is(event.target.transaction.mode, "versionchange",
        "transaction has the correct mode");
     is(event.target.transaction.objectStoreNames.length, index + 1,
        "transaction has correct objectStoreNames list");
     found = false;
     for (let j = 0; j < event.target.transaction.objectStoreNames.length;
          j++) {
       if (event.target.transaction.objectStoreNames.item(j) == name) {
         found = true;
--- a/dom/indexedDB/test/unit/test_cursor_mutation.js
+++ b/dom/indexedDB/test/unit/test_cursor_mutation.js
@@ -66,17 +66,17 @@ function testSteps()
   is(count, objectStoreData.length - 1, "Good initial count");
   is(sawAdded, false, "Didn't see item that is about to be added");
   is(sawRemoved, true, "Saw item that is about to be removed");
 
   count = 0;
   sawAdded = false;
   sawRemoved = false;
 
-  db.transaction("foo", IDBTransaction.READ_WRITE).objectStore("foo")
+  db.transaction("foo", "readwrite").objectStore("foo")
     .index("name").openCursor().onsuccess = function(event) {
       event.target.transaction.oncomplete = continueToNextStep;
       let cursor = event.target.result;
       if (cursor) {
         if (cursor.value.name == objectStoreData[0].name) {
           sawRemoved = true;
         }
         if (cursor.value.name ==
--- a/dom/indexedDB/test/unit/test_cursor_update_updates_indexes.js
+++ b/dom/indexedDB/test/unit/test_cursor_update_updates_indexes.js
@@ -2,19 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
-  const nsIIDBTransaction = Components.interfaces.nsIIDBTransaction;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
   const START_DATA = "hi";
   const END_DATA = "bye";
   const objectStoreInfo = [
     { name: "1", options: { keyPath: null }, key: 1,
       entry: { data: START_DATA } },
     { name: "2", options: { keyPath: "foo" },
--- a/dom/indexedDB/test/unit/test_cursors.js
+++ b/dom/indexedDB/test/unit/test_cursors.js
@@ -281,17 +281,17 @@ function testSteps()
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   keyIndex = 0;
 
   let gotRemoveEvent = false;
   let retval = false;
 
-  request = objectStore.openCursor(null, IDBCursor.NEXT);
+  request = objectStore.openCursor(null, "next");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, sortedKeys[keyIndex], "Correct key");
       is(cursor.primaryKey, sortedKeys[keyIndex], "Correct primary key");
       is(cursor.value, "foo", "Correct value");
 
@@ -326,17 +326,17 @@ function testSteps()
 
   request = objectStore.add("foo", sortedKeys[4]);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   keyIndex = sortedKeys.length - 1;
 
-  request = objectStore.openCursor(null, IDBCursor.PREV);
+  request = objectStore.openCursor(null, "prev");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, sortedKeys[keyIndex], "Correct key");
       is(cursor.primaryKey, sortedKeys[keyIndex], "Correct primary key");
       is(cursor.value, "foo", "Correct value");
 
--- a/dom/indexedDB/test/unit/test_index_empty_keyPath.js
+++ b/dom/indexedDB/test/unit/test_index_empty_keyPath.js
@@ -38,17 +38,17 @@ function testSteps()
     }
   }
   event = yield; // testGenerator.send
 
   // Now create the index.
   objectStore.createIndex("set", "", { unique: true });
   yield; // success
 
-  let trans = db.transaction("data", IDBTransaction.READ_WRITE);
+  let trans = db.transaction("data", "readwrite");
   objectStore = trans.objectStore("data");
   index = objectStore.index("set");
 
   let request = index.get("bar");
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   
   let event = yield;
--- a/dom/indexedDB/test/unit/test_index_object_cursors.js
+++ b/dom/indexedDB/test/unit/test_index_object_cursors.js
@@ -52,17 +52,17 @@ function testSteps()
   for (let objectStoreIndex in objectStoreData) {
     const info = objectStoreData[objectStoreIndex];
 
     for (let indexIndex in indexData) {
       const objectStoreName = objectStoreData[objectStoreIndex].name;
       const indexName = indexData[indexIndex].name;
 
       let objectStore =
-        db.transaction(objectStoreName, IDBTransaction.READ_WRITE)
+        db.transaction(objectStoreName, "readwrite")
           .objectStore(objectStoreName);
       ok(true, "Got objectStore " + objectStoreName);
 
       for (let dataIndex in data) {
         const obj = data[dataIndex];
         let key;
         if (!info.options.keyPath && !info.options.autoIncrement) {
           key = obj.ss;
@@ -128,17 +128,17 @@ function testSteps()
 
         cursor.continue();
         keyIndex++;
       };
       yield;
 
       is(keyIndex, 1, "Saw all the items");
 
-      db.transaction(objectStoreName, IDBTransaction.READ_WRITE)
+      db.transaction(objectStoreName, "readwrite")
         .objectStore(objectStoreName).clear()
         .onsuccess = continueToNextStep;
       yield;
     }
   }
 
   finishTest();
   yield;
--- a/dom/indexedDB/test/unit/test_index_update_delete.js
+++ b/dom/indexedDB/test/unit/test_index_update_delete.js
@@ -47,17 +47,17 @@ function testSteps()
     let event = yield;
 
     is(event.target.result, 20, "Correct number of entries in objectStore");
 
     let objectStoreCount = event.target.result;
     let indexCount = event.target.result;
 
     for each (let unique in [false, true]) {
-      let index = db.transaction(autoIncrement, IDBTransaction.READ_WRITE)
+      let index = db.transaction(autoIncrement, "readwrite")
                     .objectStore(autoIncrement)
                     .index(unique);
 
       index.count().onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       is(event.target.result, indexCount,
          "Correct number of entries in index");
@@ -81,17 +81,17 @@ function testSteps()
           continueToNextStep();
         }
       }
       yield;
 
       is(sawEntry, true, "Saw entry for key value " + modifiedEntry);
 
       // Recount index. Shouldn't change.
-      index = db.transaction(autoIncrement, IDBTransaction.READ_WRITE)
+      index = db.transaction(autoIncrement, "readwrite")
                 .objectStore(autoIncrement)
                 .index(unique);
 
       index.count().onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       is(event.target.result, indexCount,
          "Correct number of entries in index");
@@ -116,17 +116,17 @@ function testSteps()
           continueToNextStep();
         }
       }
       yield;
 
       is(sawEntry, true, "Saw entry for key value " + modifiedEntry);
 
       // Recount objectStore. Should be unchanged.
-      objectStore = db.transaction(autoIncrement, IDBTransaction.READ_WRITE)
+      objectStore = db.transaction(autoIncrement, "readwrite")
                       .objectStore(autoIncrement);
 
       objectStore.count().onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       is(event.target.result, objectStoreCount,
          "Correct number of entries in objectStore");
 
--- a/dom/indexedDB/test/unit/test_indexes.js
+++ b/dom/indexedDB/test/unit/test_indexes.js
@@ -4,23 +4,16 @@
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const CONSTRAINT_ERR =
     Components.interfaces.nsIIDBDatabaseException.CONSTRAINT_ERR;
-  const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-  const NEXT = Components.interfaces.nsIIDBCursor.NEXT;
-  const PREV = Components.interfaces.nsIIDBCursor.PREV;
-  const NEXT_NO_DUPLICATE =
-    Components.interfaces.nsIIDBCursor.NEXT_NO_DUPLICATE;
-  const PREV_NO_DUPLICATE =
-    Components.interfaces.nsIIDBCursor.PREV_NO_DUPLICATE;
 
   const name = this.window ? this.window ? window.location.pathname : "Splendid Test" : "Splendid Test";
   const description = "My Test Database";
 
   const objectStoreName = "People";
 
   const objectStoreData = [
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
@@ -162,17 +155,17 @@ function testSteps()
   yield;
 
   is(keyIndex, objectStoreData.length, "Saw all the expected keys");
 
   ok(true, "Test group 2");
 
   keyIndex = 0;
 
-  request = objectStore.index("weight").openKeyCursor(null, NEXT);
+  request = objectStore.index("weight").openKeyCursor(null, "next");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataWeightSort[keyIndex].value.weight,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataWeightSort[keyIndex].key,
          "Correct value");
@@ -190,29 +183,29 @@ function testSteps()
       testGenerator.next();
     }
   }
   yield;
 
   is(keyIndex, objectStoreData.length - 1, "Saw all the expected keys");
 
   // Check that the name index enforces its unique constraint.
-  objectStore = db.transaction(objectStoreName, READ_WRITE)
+  objectStore = db.transaction(objectStoreName, "readwrite")
                   .objectStore(objectStoreName);
   request = objectStore.add({ name: "Bob", height: 62, weight: 170 },
                             "237-23-7738");
   request.onerror = new ExpectError(CONSTRAINT_ERR);
   request.onsuccess = unexpectedSuccessHandler;
   event = yield;
 
   ok(true, "Test group 3");
 
   keyIndex = objectStoreDataNameSort.length - 1;
 
-  request = objectStore.index("name").openKeyCursor(null, PREV);
+  request = objectStore.index("name").openKeyCursor(null, "prev");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataNameSort[keyIndex].key,
          "Correct value");
@@ -518,17 +511,17 @@ function testSteps()
   yield;
 
   is(keyIndex, objectStoreDataNameSort.length, "Saw all the expected keys");
 
   ok(true, "Test group 14");
 
   keyIndex = objectStoreDataNameSort.length - 1;
 
-  request = objectStore.index("name").openCursor(null, PREV);
+  request = objectStore.index("name").openCursor(null, "prev");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataNameSort[keyIndex].key,
          "Correct primary key");
@@ -778,17 +771,17 @@ function testSteps()
 
   is(keyIndex, 4, "Saw all the expected keys");
 
   ok(true, "Test group 19");
 
   keyIndex = 4;
   keyRange = IDBKeyRange.bound("Bob", "Ron");
 
-  request = objectStore.index("name").openCursor(keyRange, PREV);
+  request = objectStore.index("name").openCursor(keyRange, "prev");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataNameSort[keyIndex].value.name,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataNameSort[keyIndex].key,
          "Correct primary key");
@@ -827,21 +820,21 @@ function testSteps()
     }
   }
   yield;
 
   is(keyIndex, 0, "Saw all the expected keys");
 
   ok(true, "Test group 20");
 
-  // Test NEXT_NO_DUPLICATE
+  // Test "nextunique"
   keyIndex = 3;
   keyRange = IDBKeyRange.only(65);
 
-  request = objectStore.index("height").openKeyCursor(keyRange, NEXT);
+  request = objectStore.index("height").openKeyCursor(keyRange, "next");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct value");
@@ -858,17 +851,17 @@ function testSteps()
   is(keyIndex, 5, "Saw all the expected keys");
 
   ok(true, "Test group 21");
 
   keyIndex = 3;
   keyRange = IDBKeyRange.only(65);
 
   request = objectStore.index("height").openKeyCursor(keyRange,
-                                                      NEXT_NO_DUPLICATE);
+                                                      "nextunique");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct value");
@@ -883,17 +876,17 @@ function testSteps()
   yield;
 
   is(keyIndex, 4, "Saw all the expected keys");
 
   ok(true, "Test group 21.5");
 
   keyIndex = 5;
 
-  request = objectStore.index("height").openKeyCursor(null, PREV);
+  request = objectStore.index("height").openKeyCursor(null, "prev");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct value");
@@ -909,17 +902,17 @@ function testSteps()
 
   is(keyIndex, -1, "Saw all the expected keys");
 
   ok(true, "Test group 22");
 
   keyIndex = 5;
 
   request = objectStore.index("height").openKeyCursor(null,
-                                                      PREV_NO_DUPLICATE);
+                                                      "prevunique");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct value");
@@ -938,17 +931,17 @@ function testSteps()
 
   is(keyIndex, -1, "Saw all the expected keys");
 
   ok(true, "Test group 23");
 
   keyIndex = 3;
   keyRange = IDBKeyRange.only(65);
 
-  request = objectStore.index("height").openCursor(keyRange, NEXT);
+  request = objectStore.index("height").openCursor(keyRange, "next");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct primary key");
@@ -975,17 +968,17 @@ function testSteps()
   is(keyIndex, 5, "Saw all the expected keys");
 
   ok(true, "Test group 24");
 
   keyIndex = 3;
   keyRange = IDBKeyRange.only(65);
 
   request = objectStore.index("height").openCursor(keyRange,
-                                                   NEXT_NO_DUPLICATE);
+                                                   "nextunique");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct primary key");
@@ -1010,17 +1003,17 @@ function testSteps()
   yield;
 
   is(keyIndex, 4, "Saw all the expected keys");
 
   ok(true, "Test group 24.5");
 
   keyIndex = 5;
 
-  request = objectStore.index("height").openCursor(null, PREV);
+  request = objectStore.index("height").openCursor(null, "prev");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct primary key");
@@ -1046,17 +1039,17 @@ function testSteps()
 
   is(keyIndex, -1, "Saw all the expected keys");
 
   ok(true, "Test group 25");
 
   keyIndex = 5;
 
   request = objectStore.index("height").openCursor(null,
-                                                   PREV_NO_DUPLICATE);
+                                                   "prevunique");
   request.onerror = errorHandler;
   request.onsuccess = function (event) {
     let cursor = event.target.result;
     if (cursor) {
       is(cursor.key, objectStoreDataHeightSort[keyIndex].value.height,
          "Correct key");
       is(cursor.primaryKey, objectStoreDataHeightSort[keyIndex].key,
          "Correct primary key");
--- a/dom/indexedDB/test/unit/test_indexes_bad_values.js
+++ b/dom/indexedDB/test/unit/test_indexes_bad_values.js
@@ -4,17 +4,16 @@
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const CONSTRAINT_ERR =
     Components.interfaces.nsIIDBDatabaseException.CONSTRAINT_ERR;
-  const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
 
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
 
   const objectStoreName = "People";
 
   const objectStoreData = [
     { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
--- a/dom/indexedDB/test/unit/test_keys.js
+++ b/dom/indexedDB/test/unit/test_keys.js
@@ -3,17 +3,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const dbname = this.window ? window.location.pathname : "Splendid Test";
-  const RW = IDBTransaction.READ_WRITE
+  const RW = "readwrite"
   let c1 = 1;
   let c2 = 1;
 
   let openRequest = mozIndexedDB.open(dbname, 1);
   openRequest.onerror = errorHandler;
   openRequest.onupgradeneeded = grabEventAndContinueHandler;
   openRequest.onsuccess = unexpectedSuccessHandler;
   let event = yield;
--- a/dom/indexedDB/test/unit/test_multientry.js
+++ b/dom/indexedDB/test/unit/test_multientry.js
@@ -202,17 +202,17 @@ function testSteps()
     is(req.result, undefined, "exhausted temp index");
     store.deleteIndex("temp index");
   }
 
 
   openRequest.onsuccess = grabEventAndContinueHandler;
   yield;
 
-  let trans = db.transaction(["mystore"], IDBTransaction.READ_WRITE);
+  let trans = db.transaction(["mystore"], "readwrite");
   store = trans.objectStore("mystore");
   index = store.index("myindex");
   is(index.multiEntry, true, "index still is multiEntry");
   trans.oncomplete = grabEventAndContinueHandler;
   yield;
 
   finishTest();
   yield;
--- a/dom/indexedDB/test/unit/test_odd_result_order.js
+++ b/dom/indexedDB/test/unit/test_odd_result_order.js
@@ -22,17 +22,17 @@ function testSteps()
 
   let objectStore = db.createObjectStore("foo", { keyPath: "key",
                                                   autoIncrement: true });
   let index = objectStore.createIndex("foo", "index");
 
   event.target.onsuccess = continueToNextStep;
   yield;
 
-  objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)
+  objectStore = db.transaction("foo", "readwrite")
                   .objectStore("foo");
   request = objectStore.add(data);
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   let key;
   executeSoon(function() {
     key = request.result;
@@ -51,17 +51,17 @@ function testSteps()
     obj = event.target.result;
     continueToNextStep();
   });
   yield;
 
   is(obj.key, data.key, "Got the right key");
   is(obj.index, data.index, "Got the right property value");
 
-  objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)
+  objectStore = db.transaction("foo", "readwrite")
                   .objectStore("foo");
   request = objectStore.delete(data.key);
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   key = undefined;
   executeSoon(function() {
     key = request.result;
--- a/dom/indexedDB/test/unit/test_optionalArguments.js
+++ b/dom/indexedDB/test/unit/test_optionalArguments.js
@@ -147,17 +147,17 @@ function testSteps()
 
   keyRange = IDBKeyRange.bound(data[2].ssn, data[4].ssn, true);
 
   objectStore.get(keyRange).onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   is(event.target.result.name, data[3].name, "Correct data");
 
-  objectStore = db.transaction(osName, IDBTransaction.READ_WRITE)
+  objectStore = db.transaction(osName, "readwrite")
                   .objectStore(osName);
 
   try {
     objectStore.delete();
     ok(false, "Delete with unspecified arg should have thrown");
   }
   catch(e) {
     ok(true, "Delete with unspecified arg should have thrown");
--- a/dom/indexedDB/test/unit/test_overlapping_transactions.js
+++ b/dom/indexedDB/test/unit/test_overlapping_transactions.js
@@ -2,18 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
   const objectStores = [ "foo", "bar" ];
 
   let request = mozIndexedDB.open(name, 1, description);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
@@ -28,57 +26,57 @@ function testSteps()
   let event = yield;
 
   is(db.objectStoreNames.length, objectStores.length,
      "Correct objectStoreNames list");
 
   for (let i = 0; i < 50; i++) {
     let stepNumber = 0;
 
-    request = db.transaction(["foo"], READ_WRITE)
+    request = db.transaction(["foo"], "readwrite")
                 .objectStore("foo")
                 .add({});
     request.onerror = errorHandler;
     request.onsuccess = function(event) {
       is(stepNumber, 1, "This callback came first");
       stepNumber++;
       event.target.transaction.oncomplete = grabEventAndContinueHandler;
     }
 
-    request = db.transaction(["foo"], READ_WRITE)
+    request = db.transaction(["foo"], "readwrite")
                 .objectStore("foo")
                 .add({});
     request.onerror = errorHandler;
     request.onsuccess = function(event) {
       is(stepNumber, 2, "This callback came second");
       stepNumber++;
       event.target.transaction.oncomplete = grabEventAndContinueHandler;      
     }
 
-    request = db.transaction(["foo", "bar"], READ_WRITE)
+    request = db.transaction(["foo", "bar"], "readwrite")
                 .objectStore("bar")
                 .add({});
     request.onerror = errorHandler;
     request.onsuccess = function(event) {
       is(stepNumber, 3, "This callback came third");
       stepNumber++;
       event.target.transaction.oncomplete = grabEventAndContinueHandler;      
     }
 
-    request = db.transaction(["foo", "bar"], READ_WRITE)
+    request = db.transaction(["foo", "bar"], "readwrite")
                 .objectStore("bar")
                 .add({});
     request.onerror = errorHandler;
     request.onsuccess = function(event) {
       is(stepNumber, 4, "This callback came fourth");
       stepNumber++;
       event.target.transaction.oncomplete = grabEventAndContinueHandler;
     }
 
-    request = db.transaction(["bar"], READ_WRITE)
+    request = db.transaction(["bar"], "readwrite")
                 .objectStore("bar")
                 .add({});
     request.onerror = errorHandler;
     request.onsuccess = function(event) {
       is(stepNumber, 5, "This callback came fifth");
       stepNumber++;
       event.target.transaction.oncomplete = grabEventAndContinueHandler;
     }
--- a/dom/indexedDB/test/unit/test_request_readyState.js
+++ b/dom/indexedDB/test/unit/test_request_readyState.js
@@ -5,47 +5,44 @@
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
 
-  const LOADING = Components.interfaces.nsIIDBRequest.LOADING;
-  const DONE = Components.interfaces.nsIIDBRequest.DONE;
-
   let request = mozIndexedDB.open(name, 1, description);
-  is(request.readyState, LOADING, "Correct readyState");
+  is(request.readyState, "pending", "Correct readyState");
 
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
-  is(request.readyState, DONE, "Correct readyState");
+  is(request.readyState, "done", "Correct readyState");
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore("foo");
   let key = 10;
 
   request = objectStore.add({}, key);
-  is(request.readyState, LOADING, "Correct readyState");
+  is(request.readyState, "pending", "Correct readyState");
 
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
-  is(request.readyState, DONE, "Correct readyState");
+  is(request.readyState, "done", "Correct readyState");
   is(event.target.result, key, "Correct key");
 
   request = objectStore.get(key);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
-  is(request.readyState, LOADING, "Correct readyState");
+  is(request.readyState, "pending", "Correct readyState");
   event = yield;
 
   ok(event.target.result, "Got something");
-  is(request.readyState, DONE, "Correct readyState");
+  is(request.readyState, "done", "Correct readyState");
 
   finishTest();
   yield;
 }
--- a/dom/indexedDB/test/unit/test_setVersion.js
+++ b/dom/indexedDB/test/unit/test_setVersion.js
@@ -2,19 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-  const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
 
   let request = mozIndexedDB.open(name, 1, description);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
@@ -36,17 +33,17 @@ function testSteps()
     let request = mozIndexedDB.open(name, version, description);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     let event = yield;
 
     let db = event.target.result;
 
     is(db.version, version, "Database version number updated correctly");
-    is(event.target.transaction.mode, VERSION_CHANGE, "Correct mode");
+    is(event.target.transaction.mode, "versionchange", "Correct mode");
 
     executeSoon(function() { testGenerator.next(); });
     yield;
     db.close();
   }
 
   finishTest();
   yield;
--- a/dom/indexedDB/test/unit/test_setVersion_abort.js
+++ b/dom/indexedDB/test/unit/test_setVersion_abort.js
@@ -2,19 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-  const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
 
   let request = mozIndexedDB.open(name, 1, description);
   request.onerror = grabEventAndContinueHandler;
   request.onsuccess = unexpectedSuccessHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
--- a/dom/indexedDB/test/unit/test_setVersion_events.js
+++ b/dom/indexedDB/test/unit/test_setVersion_events.js
@@ -52,17 +52,17 @@ function testSteps()
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onblocked = errorHandler;
   event = yield;
 
   // Test the upgradeneeded event.
   ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
   ok(event.target.result instanceof IDBDatabase, "Good result");
   db2 = event.target.result;
-  is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
+  is(event.target.transaction.mode, "versionchange",
      "Correct mode");
   is(db2.version, 2, "Correct db version");
   is(event.oldVersion, 1, "Correct event oldVersion");
   is(event.newVersion, 2, "Correct event newVersion");
 
   request.onupgradeneeded = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
@@ -122,17 +122,17 @@ function testSteps()
   request.onsuccess = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onblocked = errorHandler;
 
   event = yield;
 
   ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
   ok(event.target.result instanceof IDBDatabase, "Good result");
-  is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
+  is(event.target.transaction.mode, "versionchange",
      "Correct mode");
   is(event.oldVersion, 3, "Correct event oldVersion");
   is(event.newVersion, 4, "Correct event newVersion");
 
   request.onsuccess = grabEventAndContinueHandler;
 
   event = yield;
   ok(event.target.result instanceof IDBDatabase, "Expect a database here");
--- a/dom/indexedDB/test/unit/test_transaction_abort.js
+++ b/dom/indexedDB/test/unit/test_transaction_abort.js
@@ -8,24 +8,16 @@ var testGenerator = testSteps();
 var abortFired = false;
 
 function abortListener() { abortFired = true; }
 
 function testSteps()
 {
   const Ci = Components.interfaces;
 
-  const INITIAL = Ci.nsIIDBTransaction.INITIAL;
-  const LOADING = Ci.nsIIDBTransaction.LOADING;
-  const COMMITTING = Ci.nsIIDBTransaction.COMMITTING;
-  const DONE = Ci.nsIIDBTransaction.DONE;
-  const READ_ONLY = Ci.nsIIDBTransaction.READ_ONLY;
-  const READ_WRITE = Ci.nsIIDBTransaction.READ_WRITE;
-  const VERSION_CHANGE = Ci.nsIIDBTransaction.VERSION_CHANGE;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
 
 
   let request = mozIndexedDB.open(name, 1, description);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
@@ -38,18 +30,17 @@ function testSteps()
   let objectStore;
   let index;
 
   transaction = event.target.transaction;
   objectStore = db.createObjectStore("foo", { autoIncrement: true });
   index = objectStore.createIndex("fooindex", "indexKey", { unique: true });
 
   is(transaction.db, db, "Correct database");
-  is(transaction.readyState, LOADING, "Correct readyState");
-  is(transaction.mode, VERSION_CHANGE, "Correct mode");
+  is(transaction.mode, "versionchange", "Correct mode");
   is(transaction.objectStoreNames.length, 1, "Correct names length");
   is(transaction.objectStoreNames.item(0), "foo", "Correct name");
   is(transaction.objectStore("foo"), objectStore, "Can get stores");
   is(transaction.oncomplete, null, "No complete listener");
   is(transaction.onabort, null, "No abort listener");
 
   is(objectStore.name, "foo", "Correct name");
   is(objectStore.keyPath, null, "Correct keyPath");
@@ -58,18 +49,17 @@ function testSteps()
   is(objectStore.indexNames[0], "fooindex", "Correct indexNames name");
   is(objectStore.index("fooindex"), index, "Can get index");
 
   // Wait until it's complete!
   transaction.oncomplete = grabEventAndContinueHandler;
   event = yield;
 
   is(transaction.db, db, "Correct database");
-  is(transaction.readyState, DONE, "Correct readyState");
-  is(transaction.mode, VERSION_CHANGE, "Correct mode");
+  is(transaction.mode, "versionchange", "Correct mode");
   is(transaction.objectStoreNames.length, 1, "Correct names length");
   is(transaction.objectStoreNames.item(0), "foo", "Correct name");
   is(transaction.onabort, null, "No abort listener");
 
   try {
     is(transaction.objectStore("foo").name, "foo", "Can't get stores");
     ok(false, "Should have thrown");
   }
@@ -160,46 +150,44 @@ function testSteps()
     ok(false, "Should have thrown");
   }
   catch (e) {
     ok(true, "RemoveIndex threw");
   }
 
   yield;
 
-  request = db.transaction("foo", READ_WRITE).objectStore("foo").add({});
+  request = db.transaction("foo", "readwrite").objectStore("foo").add({});
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   event.target.transaction.onabort = function(event) {
     ok(false, "Shouldn't see an abort event!");
   };
   event.target.transaction.oncomplete = grabEventAndContinueHandler;
   event = yield;
 
   is(event.type, "complete", "Right kind of event");
 
   let key;
 
-  request = db.transaction("foo", READ_WRITE).objectStore("foo").add({});
+  request = db.transaction("foo", "readwrite").objectStore("foo").add({});
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
   key = event.target.result;
 
   event.target.transaction.onabort = grabEventAndContinueHandler;
   event.target.transaction.oncomplete = function(event) {
     ok(false, "Shouldn't see a complete event here!");
   };
 
-  is(event.target.transaction.readyState, LOADING, "Correct readyState");
   event.target.transaction.abort();
-  is(event.target.transaction.readyState, DONE, "Correct readyState");
 
   event = yield;
 
   is(event.type, "abort", "Right kind of event");
 
   request = db.transaction("foo").objectStore("foo").get(key);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
@@ -213,17 +201,17 @@ function testSteps()
   let keys = [];
   let abortEventCount = 0;
   function abortErrorHandler(event) {
       is(event.target.errorCode, IDBDatabaseException.ABORT_ERR,
          "Good code");
       abortEventCount++;
       event.preventDefault();
   };
-  objectStore = db.transaction("foo", READ_WRITE).objectStore("foo");
+  objectStore = db.transaction("foo", "readwrite").objectStore("foo");
 
   for (let i = 0; i < 10; i++) {
     request = objectStore.add({});
     request.onerror = abortErrorHandler;
     request.onsuccess = function(event) {
       keys.push(event.target.result);
       if (keys.length == 5) {
         event.target.transaction.onabort = grabEventAndContinueHandler;
@@ -242,17 +230,17 @@ function testSteps()
     request.onerror = errorHandler;
     request.onsuccess = grabEventAndContinueHandler;
     event = yield;
 
     is(event.target.result, undefined, "Object was removed by abort");
   }
 
   // Set up some predictible data
-  transaction = db.transaction("foo", READ_WRITE);
+  transaction = db.transaction("foo", "readwrite");
   objectStore = transaction.objectStore("foo");
   objectStore.clear();
   objectStore.add({}, 1);
   objectStore.add({}, 2);
   request = objectStore.add({}, 1);
   request.onsuccess = function() {
     ok(false, "inserting duplicate key should fail");
   }
@@ -264,118 +252,106 @@ function testSteps()
   yield;
 
   // Check when aborting is allowed
   abortEventCount = 0;
   let expectedAbortEventCount = 0;
 
   // During INITIAL
   transaction = db.transaction("foo");
-  is(transaction.readyState, INITIAL, "in INITIAL state");
   transaction.abort();
-  is(transaction.readyState, DONE, "in DONE state after abort()");
   try {
     transaction.abort();
     ok(false, "second abort should throw an error");
   }
   catch (ex) {
     ok(true, "second abort should throw an error");
   }
 
   // During LOADING
   transaction = db.transaction("foo");
   transaction.objectStore("foo").get(1).onerror = abortErrorHandler;
   expectedAbortEventCount++;
-  is(transaction.readyState, LOADING, "in LOADING state");
   transaction.abort();
-  is(transaction.readyState, DONE, "in DONE state after abort()");
   try {
     transaction.abort();
     ok(false, "second abort should throw an error");
   }
   catch (ex) {
     ok(true, "second abort should throw an error");
   }
 
   // During LOADING from callback
   transaction = db.transaction("foo");
   transaction.objectStore("foo").get(1).onsuccess = grabEventAndContinueHandler;
   event = yield;
   transaction.objectStore("foo").get(1).onerror = abortErrorHandler;
   expectedAbortEventCount++
-  is(transaction.readyState, LOADING, "in LOADING state");
   transaction.abort();
-  is(transaction.readyState, DONE, "in DONE state after abort()");
   try {
     transaction.abort();
     ok(false, "second abort should throw an error");
   }
   catch (ex) {
     ok(true, "second abort should throw an error");
   }
 
   // During LOADING from error callback
-  transaction = db.transaction("foo", READ_WRITE);
+  transaction = db.transaction("foo", "readwrite");
   transaction.objectStore("foo").add({}, 1).onerror = function(event) {
     event.preventDefault();
 
     transaction.objectStore("foo").get(1).onerror = abortErrorHandler;
     expectedAbortEventCount++
 
-    is(transaction.readyState, LOADING, "in LOADING state");
     transaction.abort();
-    is(transaction.readyState, DONE, "in DONE state after abort()");
     continueToNextStep();
   }
   yield;
 
   // In between callbacks
   transaction = db.transaction("foo");
   function makeNewRequest() {
     let r = transaction.objectStore("foo").get(1);
     r.onsuccess = makeNewRequest;
     r.onerror = abortErrorHandler;
   }
   makeNewRequest();
   transaction.objectStore("foo").get(1).onsuccess = function(event) {
     executeSoon(function() {
-      is(transaction.readyState, LOADING, "in LOADING state");
       transaction.abort();
       expectedAbortEventCount++;
-      is(transaction.readyState, DONE, "in DONE state after abort()");
       continueToNextStep();
     });
   };
   yield;
   
   // During COMMITTING
-  transaction = db.transaction("foo", READ_WRITE);
+  transaction = db.transaction("foo", "readwrite");
   transaction.objectStore("foo").put({hello: "world"}, 1).onsuccess = function(event) {
     continueToNextStep();
   };
   yield;
-  is(transaction.readyState, COMMITTING, "in COMMITTING state");
   try {
     transaction.abort();
     ok(false, "second abort should throw an error");
   }
   catch (ex) {
     ok(true, "second abort should throw an error");
   }
   transaction.oncomplete = grabEventAndContinueHandler;
   event = yield;
-  is(transaction.readyState, DONE, "in DONE state");
 
   // Since the previous transaction shouldn't have caused any error events,
   // we know that all events should have fired by now.
   is(abortEventCount, expectedAbortEventCount,
      "All abort errors fired");
 
   // Abort both failing and succeeding requests
-  transaction = db.transaction("foo", READ_WRITE);
+  transaction = db.transaction("foo", "readwrite");
   transaction.onabort = transaction.oncomplete = grabEventAndContinueHandler;
   transaction.objectStore("foo").add({indexKey: "key"}).onsuccess = function(event) {
     transaction.abort();
   };
   let request1 = transaction.objectStore("foo").add({indexKey: "key"});
   request1.onsuccess = grabEventAndContinueHandler;
   request1.onerror = grabEventAndContinueHandler;
   let request2 = transaction.objectStore("foo").get(1);
--- a/dom/indexedDB/test/unit/test_transaction_lifetimes_nested.js
+++ b/dom/indexedDB/test/unit/test_transaction_lifetimes_nested.js
@@ -15,49 +15,37 @@ function testSteps()
   let db = event.target.result;
   db.onerror = errorHandler;
 
   event.target.onsuccess = continueToNextStep;
   db.createObjectStore("foo");
   yield;
 
   let transaction1 = db.transaction("foo");
-  is(transaction1.readyState, IDBTransaction.INITIAL, "Correct readyState");
 
   let transaction2;
 
   if (this.window)
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   let thread = Components.classes["@mozilla.org/thread-manager;1"]
                          .getService()
                          .currentThread;
 
   let eventHasRun;
 
   thread.dispatch(function() {
     eventHasRun = true;
 
-    is(transaction1.readyState, IDBTransaction.INITIAL,
-       "Correct readyState");
-
     transaction2 = db.transaction("foo");
-    is(transaction2.readyState, IDBTransaction.INITIAL,
-       "Correct readyState");
-
   }, Components.interfaces.nsIThread.DISPATCH_NORMAL);
 
   while (!eventHasRun) {
     thread.processNextEvent(false);
   }
 
-  is(transaction1.readyState, IDBTransaction.INITIAL, "Correct readyState");
-
   ok(transaction2, "Non-null transaction2");
-  is(transaction2.readyState, IDBTransaction.DONE, "Correct readyState");
 
   continueToNextStep();
   yield;
 
-  is(transaction1.readyState, IDBTransaction.DONE, "Correct readyState");
-
   finishTest();
   yield;
 }
--- a/dom/indexedDB/test/unit/test_transaction_ordering.js
+++ b/dom/indexedDB/test/unit/test_transaction_ordering.js
@@ -15,32 +15,32 @@ function testSteps()
   let db = event.target.result;
   db.onerror = errorHandler;
 
   request.onsuccess = continueToNextStep;
 
   db.createObjectStore("foo");
   yield;
 
-  let trans1 = db.transaction("foo", IDBTransaction.READ_WRITE);
-  let trans2 = db.transaction("foo", IDBTransaction.READ_WRITE);
+  let trans1 = db.transaction("foo", "readwrite");
+  let trans2 = db.transaction("foo", "readwrite");
 
   let request1 = trans2.objectStore("foo").put("2", 42);
   let request2 = trans1.objectStore("foo").put("1", 42);
 
   request1.onerror = errorHandler;
   request2.onerror = errorHandler;
 
   trans1.oncomplete = grabEventAndContinueHandler;
   trans2.oncomplete = grabEventAndContinueHandler;
 
   yield;
   yield;
 
-  let trans3 = db.transaction("foo", IDBTransaction.READ);
+  let trans3 = db.transaction("foo", "readonly");
   let request = trans3.objectStore("foo").get(42);
   request.onsuccess = grabEventAndContinueHandler;
   request.onerror = errorHandler;
 
   let event = yield;
   is(event.target.result, "2", "Transactions were ordered properly.");
 
   finishTest();
--- a/dom/indexedDB/test/unit/test_writer_starvation.js
+++ b/dom/indexedDB/test/unit/test_writer_starvation.js
@@ -2,33 +2,28 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
-  const READ_ONLY = Components.interfaces.nsIIDBTransaction.READ_ONLY;
-  const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
-  const VERSION_CHANGE =
-    Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
-
   const name = this.window ? window.location.pathname : "Splendid Test";
   const description = "My Test Database";
 
   let request = mozIndexedDB.open(name, 1, description);
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
-  is(event.target.transaction.mode, VERSION_CHANGE, "Correct mode");
+  is(event.target.transaction.mode, "versionchange", "Correct mode");
 
   let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
   request = objectStore.add({});
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
 
@@ -53,20 +48,20 @@ function testSteps()
     };
   }
 
   while (continueReading) {
     readerCount++;
     request = db.transaction("foo").objectStore("foo").get(key);
     request.onerror = errorHandler;
     request.onsuccess = function(event) {
-      is(event.target.transaction.mode, READ_ONLY, "Correct mode");
+      is(event.target.transaction.mode, "readonly", "Correct mode");
       callbackCount++;
       if (callbackCount == 100) {
-        request = db.transaction("foo", READ_WRITE)
+        request = db.transaction("foo", "readwrite")
                     .objectStore("foo")
                     .add({}, readerCount);
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
           continueReading = false;
           finalCallbackCount = callbackCount;
           is(event.target.result, callbackCount,
              "write callback came before later reads");
--- a/dom/interfaces/events/nsIDOMCloseEvent.idl
+++ b/dom/interfaces/events/nsIDOMCloseEvent.idl
@@ -55,15 +55,14 @@ interface nsIDOMCloseEvent : nsIDOMEvent
   void initCloseEvent(in DOMString aType,
                       in boolean aCanBubble,
                       in boolean aCancelable,
                       in boolean aWasClean,
                       in unsigned short aReasonCode,
                       in DOMString aReason);
 };
 
-[scriptable, uuid(148ed08e-14f1-4be5-b2f8-23f765738379)]
-interface nsICloseEventInit : nsIEventInit
+dictionary CloseEventInit : EventInit
 {
-  attribute boolean wasClean;
-  attribute unsigned short code;
-  attribute DOMString reason;
+  boolean wasClean;
+  unsigned short code;
+  DOMString reason;
 };
--- a/dom/interfaces/events/nsIDOMCustomEvent.idl
+++ b/dom/interfaces/events/nsIDOMCustomEvent.idl
@@ -45,13 +45,12 @@ interface nsIDOMCustomEvent : nsIDOMEven
   readonly attribute nsIVariant detail;
 
   void initCustomEvent(in DOMString  typeArg, 
                        in boolean    canBubbleArg, 
                        in boolean    cancelableArg, 
                        in nsIVariant detailArg);
 };
 
-[scriptable, uuid(8c166794-06af-4eac-b76b-bc132e421b06)]
-interface nsICustomEventInit : nsIEventInit
+dictionary CustomEventInit : EventInit
 {
-  attribute nsIVariant detail;
+  nsIVariant detail;
 };
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -177,14 +177,13 @@ interface nsIDOMEvent : nsISupports
 
   /**
    * Prevents other event listeners from being triggered and,
    * unlike Event.stopPropagation() its effect is immediate.
    */
   void                       stopImmediatePropagation();
 };
 
-[scriptable, uuid(fe864f0f-45df-404a-bb27-83c5d08be8d1)]
-interface nsIEventInit : nsISupports
+dictionary EventInit
 {
-  attribute boolean bubbles;
-  attribute boolean cancelable;
+  boolean bubbles;
+  boolean cancelable;
 };
--- a/dom/interfaces/events/nsIDOMHashChangeEvent.idl
+++ b/dom/interfaces/events/nsIDOMHashChangeEvent.idl
@@ -42,14 +42,13 @@ interface nsIDOMHashChangeEvent : nsIDOM
 
   void initHashChangeEvent(in DOMString typeArg,
                            in boolean canBubbleArg,
                            in boolean cancelableArg,
                            in DOMString oldURLArg,
                            in DOMString newURLArg);
 };
 
-[scriptable, uuid(e56881c1-3714-45bb-bca3-1453ea24ee90)]
-interface nsIHashChangeEventInit : nsIEventInit
+dictionary HashChangeEventInit : EventInit
 {
-  attribute DOMString oldURL;
-  attribute DOMString newURL;
+  DOMString oldURL;
+  DOMString newURL;
 };
--- a/dom/interfaces/events/nsIDOMMouseEvent.idl
+++ b/dom/interfaces/events/nsIDOMMouseEvent.idl
@@ -109,23 +109,22 @@ interface nsIDOMMouseEvent : nsIDOMUIEve
                                        in boolean shiftKeyArg,
                                        in boolean metaKeyArg,
                                        in unsigned short buttonArg,
                                        in nsIDOMEventTarget relatedTargetArg,
                                        in float pressure,
                                        in unsigned short inputSourceArg);
 };
 
-[scriptable, uuid(9495a977-5c9e-4b34-8d51-22bfd9b4fcf6)]
-interface nsIMouseEventInit : nsIUIEventInit
+dictionary MouseEventInit : UIEventInit
 {
-  attribute long screenX;
-  attribute long screenY;
-  attribute long clientX;
-  attribute long clientY;
-  attribute boolean ctrlKey;
-  attribute boolean shiftKey;
-  attribute boolean altKey;
-  attribute boolean metaKey;
-  attribute unsigned short button;
-  // attribute unsigned short buttons; is not supported yet.
-  attribute nsIDOMEventTarget relatedTarget;
+  long screenX;
+  long screenY;
+  long clientX;
+  long clientY;
+  boolean ctrlKey;
+  boolean shiftKey;
+  boolean altKey;
+  boolean metaKey;
+  unsigned short button;
+  // unsigned short buttons; is not supported yet.
+  nsIDOMEventTarget relatedTarget;
 };
--- a/dom/interfaces/events/nsIDOMPageTransitionEvent.idl
+++ b/dom/interfaces/events/nsIDOMPageTransitionEvent.idl
@@ -56,13 +56,12 @@ interface nsIDOMPageTransitionEvent : ns
 
   /* Initialize a new pageshow or pagehide event. */
   void initPageTransitionEvent(in DOMString typeArg,
                                in boolean canBubbleArg,
                                in boolean canCancelArg,
                                in boolean persisted);
 };
 
-[scriptable, uuid(bf3eaa61-5048-48c4-b8b9-9bf833ca63d6)]
-interface nsIPageTransitionEventInit : nsIEventInit
+dictionary PageTransitionEventInit : EventInit
 {
-  attribute boolean persisted;
+  boolean persisted;
 };
--- a/dom/interfaces/events/nsIDOMPopStateEvent.idl
+++ b/dom/interfaces/events/nsIDOMPopStateEvent.idl
@@ -45,13 +45,12 @@ interface nsIDOMPopStateEvent : nsIDOMEv
   readonly attribute nsIVariant state;
 
   void initPopStateEvent(in DOMString typeArg,
                          in boolean canBubbleArg,
                          in boolean cancelableArg,
                          in nsIVariant stateArg);
 };
 
-[scriptable, uuid(2300bd68-f6e0-4c58-a1aa-45f94cdabfbd)]
-interface nsIPopStateEventInit : nsIEventInit
+dictionary PopStateEventInit : EventInit
 {
-  attribute nsIVariant state;
+  nsIVariant state;
 };
--- a/dom/interfaces/events/nsIDOMUIEvent.idl
+++ b/dom/interfaces/events/nsIDOMUIEvent.idl
@@ -69,14 +69,13 @@ interface nsIDOMUIEvent : nsIDOMEvent
   readonly attribute nsIDOMNode         rangeParent;
   readonly attribute long               rangeOffset;
 
            attribute boolean            cancelBubble;
 
   readonly attribute boolean            isChar;
 };
 
-[scriptable, uuid(610eb27e-9718-4acd-8ed1-7d1840bc6c7f)]
-interface nsIUIEventInit : nsIEventInit
+dictionary UIEventInit : EventInit
 {
-  attribute nsIDOMWindow view;
-  attribute long         detail;
+  nsIDOMWindow view;
+  long         detail;
 };
--- a/dom/interfaces/storage/nsIDOMStorageEvent.idl
+++ b/dom/interfaces/storage/nsIDOMStorageEvent.idl
@@ -90,17 +90,16 @@ interface nsIDOMStorageEvent : nsIDOMEve
                         in boolean cancelableArg, 
                         in DOMString keyArg,
                         in DOMString oldValueArg,
                         in DOMString newValueArg,
                         in DOMString urlArg,
                         in nsIDOMStorage storageAreaArg);
 };
 
-[scriptable, uuid(6335e5b5-13ce-4c8a-b452-5c5895f4e90e)]
-interface nsIStorageEventInit : nsIEventInit
+dictionary StorageEventInit : EventInit
 {
-  attribute DOMString key;
-  attribute DOMString oldValue;
-  attribute DOMString newValue;
-  attribute DOMString url;
-  attribute nsIDOMStorage storageArea;
+  DOMString key;
+  DOMString? oldValue;
+  DOMString? newValue;
+  DOMString url;
+  nsIDOMStorage storageArea;
 };
--- a/dom/network/src/Connection.cpp
+++ b/dom/network/src/Connection.cpp
@@ -81,21 +81,19 @@ NS_IMPL_RELEASE_INHERITED(Connection, ns
 
 Connection::Connection()
   : mCanBeMetered(kDefaultCanBeMetered)
   , mBandwidth(kDefaultBandwidth)
 {
 }
 
 void
-Connection::Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext)
+Connection::Init(nsPIDOMWindow* aWindow)
 {
-  // Those vars come from nsDOMEventTargetHelper.
-  mOwner = aWindow;
-  mScriptContext = aScriptContext;
+  BindToOwner(aWindow);
 
   hal::RegisterNetworkObserver(this);
 
   hal::NetworkInformation networkInfo;
   hal::GetCurrentNetworkInformation(&networkInfo);
 
   UpdateFromNetworkInfo(networkInfo);
 }
--- a/dom/network/src/Connection.h
+++ b/dom/network/src/Connection.h
@@ -60,17 +60,17 @@ class Connection : public nsDOMEventTarg
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZCONNECTION
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   Connection();
 
-  void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
+  void Init(nsPIDOMWindow *aWindow);
   void Shutdown();
 
   // For IObserver
   void Notify(const hal::NetworkInformation& aNetworkInfo);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Connection,
                                            nsDOMEventTargetHelper)
 
--- a/dom/sms/interfaces/nsISmsRequestManager.idl
+++ b/dom/sms/interfaces/nsISmsRequestManager.idl
@@ -1,18 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMMozSmsMessage;
 interface nsIDOMMozSmsRequest;
-interface nsPIDOMWindow;
-interface nsIScriptContext;
+interface nsIDOMMozSmsManager;
 
 %{C++
 #define SMS_REQUEST_MANAGER_CID \
 { 0xa97a3129, 0x1e0b, 0x45da,    \
 { 0xa3, 0x85, 0xcf, 0xe5, 0xb0, 0xb1, 0xc4, 0x8f } }
 #define SMS_REQUEST_MANAGER_CONTRACTID "@mozilla.org/sms/smsrequestmanager;1"
 %}
 
@@ -31,18 +30,17 @@ interface nsISmsRequestManager : nsISupp
   const unsigned short UNKNOWN_ERROR    = 3;
   const unsigned short INTERNAL_ERROR   = 4;
 
   /**
    * Create a new request object.
    *
    * @return the request ID.
    */
-  long createRequest(in nsPIDOMWindow aWindow,
-                     in nsIScriptContext aScriptContext,
+  long createRequest(in nsIDOMMozSmsManager aManager,
                      out nsIDOMMozSmsRequest aRequest);
 
   /**
    * Track an already existing request object.
    *
    * @return the request ID.
    */
   long addRequest(in nsIDOMMozSmsRequest aRequest);
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -87,21 +87,19 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozSmsManager)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozSmsManager)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(SmsManager, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(SmsManager, nsDOMEventTargetHelper)
 
 void
-SmsManager::Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext)
+SmsManager::Init(nsPIDOMWindow *aWindow)
 {
-  // Those vars come from nsDOMEventTargetHelper.
-  mOwner = aWindow;
-  mScriptContext = aScriptContext;
+  BindToOwner(aWindow);
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   // GetObserverService() can return null is some situations like shutdown.
   if (!obs) {
     return;
   }
 
   obs->AddObserver(this, kSmsReceivedObserverTopic, false);
@@ -144,18 +142,17 @@ SmsManager::Send(JSContext* aCx, JSObjec
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDOMMozSmsRequest> request;
 
   nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
 
   PRInt32 requestId;
-  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext,
-                                              getter_AddRefs(request),
+  nsresult rv = requestManager->CreateRequest(this, getter_AddRefs(request),
                                               &requestId);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the request!");
     return rv;
   }
 
   nsDependentJSString number;
   number.init(aCx, aNumber);
@@ -169,25 +166,28 @@ SmsManager::Send(JSContext* aCx, JSObjec
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsManager::Send(const jsval& aNumber, const nsAString& aMessage, jsval* aReturn)
 {
-  JSContext* cx = mScriptContext->GetNativeContext();
+  nsresult rv;
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  NS_ENSURE_STATE(sc);
+  JSContext* cx = sc->GetNativeContext();
   NS_ASSERTION(cx, "Failed to get a context!");
 
   if (!aNumber.isString() &&
       !(aNumber.isObject() && JS_IsArrayObject(cx, &aNumber.toObject()))) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  JSObject* global = mScriptContext->GetNativeGlobal();
+  JSObject* global = sc->GetNativeGlobal();
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoRequest ar(cx);
   JSAutoEnterCompartment ac;
   if (!ac.enter(cx, global)) {
     NS_ERROR("Failed to enter the js compartment!");
     return NS_ERROR_FAILURE;
   }
@@ -221,18 +221,17 @@ SmsManager::Send(const jsval& aNumber, c
 }
 
 NS_IMETHODIMP
 SmsManager::GetMessageMoz(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
 {
   nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
 
   PRInt32 requestId;
-  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext, aRequest,
-                                              &requestId);
+  nsresult rv = requestManager->CreateRequest(this, aRequest, &requestId);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the request!");
     return rv;
   }
 
   nsCOMPtr<nsISmsDatabaseService> smsDBService =
     do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
@@ -243,18 +242,17 @@ SmsManager::GetMessageMoz(PRInt32 aId, n
 }
 
 nsresult
 SmsManager::Delete(PRInt32 aId, nsIDOMMozSmsRequest** aRequest)
 {
   nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
 
   PRInt32 requestId;
-  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext, aRequest,
-                                              &requestId);
+  nsresult rv = requestManager->CreateRequest(this, aRequest, &requestId);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the request!");
     return rv;
   }
 
   nsCOMPtr<nsISmsDatabaseService> smsDBService =
     do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE);
@@ -270,19 +268,22 @@ SmsManager::Delete(const jsval& aParam, 
   if (aParam.isInt32()) {
     return Delete(aParam.toInt32(), aRequest);
   }
 
   if (!aParam.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
+  nsresult rv;
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  NS_ENSURE_STATE(sc);
   nsCOMPtr<nsIDOMMozSmsMessage> message =
     do_QueryInterface(nsContentUtils::XPConnect()->GetNativeOfWrapper(
-          mScriptContext->GetNativeContext(), &aParam.toObject()));
+          sc->GetNativeContext(), &aParam.toObject()));
   NS_ENSURE_TRUE(message, NS_ERROR_INVALID_ARG);
 
   PRInt32 id;
   message->GetId(&id);
 
   return Delete(id, aRequest);
 }
 
@@ -294,17 +295,17 @@ SmsManager::GetMessages(nsIDOMMozSmsFilt
 
   if (!filter) {
     filter = new SmsFilter();
   }
 
   nsCOMPtr<nsISmsRequestManager> requestManager = do_GetService(SMS_REQUEST_MANAGER_CONTRACTID);
 
   PRInt32 requestId;
-  nsresult rv = requestManager->CreateRequest(mOwner, mScriptContext, aRequest,
+  nsresult rv = requestManager->CreateRequest(this, aRequest,
                                               &requestId);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the request!");
     return rv;
   }
 
   nsCOMPtr<nsISmsDatabaseService> smsDBService =
     do_GetService(SMS_DATABASE_SERVICE_CONTRACTID);
--- a/dom/sms/src/SmsManager.h
+++ b/dom/sms/src/SmsManager.h
@@ -57,17 +57,17 @@ public:
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIDOMMOZSMSMANAGER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SmsManager,
                                            nsDOMEventTargetHelper)
 
-  void Init(nsPIDOMWindow *aWindow, nsIScriptContext* aScriptContext);
+  void Init(nsPIDOMWindow *aWindow);
   void Shutdown();
 
 private:
   /**
    * Internal Send() method used to send one message.
    */
   nsresult Send(JSContext* aCx, JSObject* aGlobal, JSString* aNumber,
                 const nsAString& aMessage, jsval* aRequest);
--- a/dom/sms/src/SmsRequest.cpp
+++ b/dom/sms/src/SmsRequest.cpp
@@ -37,16 +37,17 @@
 
 #include "SmsRequest.h"
 #include "nsIDOMClassInfo.h"
 #include "nsDOMString.h"
 #include "nsContentUtils.h"
 #include "nsIDOMSmsMessage.h"
 #include "nsIDOMSmsCursor.h"
 #include "nsISmsRequestManager.h"
+#include "SmsManager.h"
 
 DOMCI_DATA(MozSmsRequest, mozilla::dom::sms::SmsRequest)
 
 namespace mozilla {
 namespace dom {
 namespace sms {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(SmsRequest)
@@ -85,25 +86,23 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(SmsRequest, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(SmsRequest, nsDOMEventTargetHelper)
 
 NS_IMPL_EVENT_HANDLER(SmsRequest, success)
 NS_IMPL_EVENT_HANDLER(SmsRequest, error)
 
-SmsRequest::SmsRequest(nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext)
+SmsRequest::SmsRequest(SmsManager* aManager)
   : mResult(JSVAL_VOID)
   , mResultRooted(false)
   , mError(nsISmsRequestManager::SUCCESS_NO_ERROR)
   , mDone(false)
 {
-  // Those vars come from nsDOMEventTargetHelper.
-  mOwner = aWindow;
-  mScriptContext = aScriptContext;
+  BindToOwner(aManager);
 }
 
 SmsRequest::~SmsRequest()
 {
   if (mResultRooted) {
     UnrootResult();
   }
 }
@@ -176,20 +175,27 @@ SmsRequest::SetSuccess(nsIDOMMozSmsCurso
 bool
 SmsRequest::SetSuccessInternal(nsISupports* aObject)
 {
   NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!");
   NS_PRECONDITION(mError == nsISmsRequestManager::SUCCESS_NO_ERROR,
                   "mError shouldn't have been set!");
   NS_PRECONDITION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
 
-  JSContext* cx = mScriptContext->GetNativeContext();
+  nsresult rv;
+  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+  if (!sc) {
+    SetError(nsISmsRequestManager::INTERNAL_ERROR);
+    return false;
+  }
+
+  JSContext* cx = sc->GetNativeContext();    
   NS_ASSERTION(cx, "Failed to get a context!");
 
-  JSObject* global = mScriptContext->GetNativeGlobal();
+  JSObject* global = sc->GetNativeGlobal();
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoRequest ar(cx);
   JSAutoEnterCompartment ac;
   if (!ac.enter(cx, global)) {
     SetError(nsISmsRequestManager::INTERNAL_ERROR);
     return false;
   }
--- a/dom/sms/src/SmsRequest.h
+++ b/dom/sms/src/SmsRequest.h
@@ -42,16 +42,17 @@
 #include "nsDOMEventTargetHelper.h"
 
 class nsIDOMMozSmsMessage;
 class nsIDOMMozSmsCursor;
 
 namespace mozilla {
 namespace dom {
 namespace sms {
+class SmsManager;
 
 class SmsRequest : public nsIDOMMozSmsRequest
                  , public nsDOMEventTargetHelper
 {
 public:
   friend class SmsRequestManager;
 
   NS_DECL_ISUPPORTS
@@ -62,17 +63,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(SmsRequest,
                                                          nsDOMEventTargetHelper)
 
   void Reset();
 
 private:
   SmsRequest() MOZ_DELETE;
 
-  SmsRequest(nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext);
+  SmsRequest(SmsManager* aManager);
   ~SmsRequest();
 
   /**
    * Root mResult (jsval) to prevent garbage collection.
    */
   void RootResult();
 
   /**
--- a/dom/sms/src/SmsRequestManager.cpp
+++ b/dom/sms/src/SmsRequestManager.cpp
@@ -34,16 +34,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "SmsRequestManager.h"
 #include "nsIDOMSmsMessage.h"
 #include "nsDOMEvent.h"
 #include "SmsCursor.h"
+#include "SmsManager.h"
 
 /**
  * We have to use macros here because our leak analysis tool things we are
  * leaking strings when we have |static const nsString|. Sad :(
  */
 #define SUCCESS_EVENT_NAME NS_LITERAL_STRING("success")
 #define ERROR_EVENT_NAME   NS_LITERAL_STRING("error")
 
@@ -73,23 +74,22 @@ SmsRequestManager::AddRequest(nsIDOMMozS
 
   mRequests.AppendObject(aRequest);
   *aRequestId = size;
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
-SmsRequestManager::CreateRequest(nsPIDOMWindow* aWindow,
-                                 nsIScriptContext* aScriptContext,
+SmsRequestManager::CreateRequest(nsIDOMMozSmsManager* aManager,
                                  nsIDOMMozSmsRequest** aRequest,
                                  PRInt32* aRequestId)
 {
   nsCOMPtr<nsIDOMMozSmsRequest> request =
-    new SmsRequest(aWindow, aScriptContext);
+    new SmsRequest(static_cast<SmsManager*>(aManager));
 
   PRInt32 size = mRequests.Count();
 
   // Look for empty slots.
   for (PRInt32 i=0; i<size; ++i) {
     if (mRequests[i]) {
       continue;
     }
--- a/dom/src/notification/nsDesktopNotification.cpp
+++ b/dom/src/notification/nsDesktopNotification.cpp
@@ -94,28 +94,25 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEve
 
 NS_IMPL_ADDREF_INHERITED(nsDOMDesktopNotification, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsDOMDesktopNotification, nsDOMEventTargetHelper)
 
 nsDOMDesktopNotification::nsDOMDesktopNotification(const nsAString & title,
                                                    const nsAString & description,
                                                    const nsAString & iconURL,
                                                    nsPIDOMWindow *aWindow,
-                                                   nsIScriptContext* aScriptContext,
                                                    nsIURI* uri)
   : mTitle(title)
   , mDescription(description)
   , mIconURL(iconURL)
   , mURI(uri)
   , mAllow(false)
   , mShowHasBeenCalled(false)
 {
-  mOwner = aWindow;
-  mScriptContext = aScriptContext;
-
+  BindToOwner(aWindow);
   if (Preferences::GetBool("notification.disabled", false)) {
     return;
   }
 
   // If we are in testing mode (running mochitests, for example)
   // and we are suppose to allow requests, then just post an allow event.
   if (Preferences::GetBool("notification.prompt.testing", false) &&