Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 15 Oct 2014 14:31:16 -0400
changeset 210557 a280a03c9f3cc6207cd17a7c76081e4e7ffd4eea
parent 210443 7de522bd978565905fb80ab17edb949bcaff41a3 (current diff)
parent 210556 1caf249e58c3024c91f5732ca00d4483a16d2e35 (diff)
child 210568 8881162414762625c8ae81f91a041e1896d5aef8
child 210578 af47efe0700909f6ebdbd7ace59b3442516800a3
child 210606 71c4f958c4aae2113a8d5ead8fb002ed3f7a15ce
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone36.0a1
Merge inbound to m-c. a=merge CLOSED TREE
browser/base/content/tabbrowser.xml
browser/modules/UITour.jsm
build/autoconf/ccache.m4
content/base/public/File.h
js/xpconnect/tests/unit/test_bug805807.js
layout/xul/nsBoxObject.cpp
layout/xul/nsBoxObject.h
layout/xul/nsContainerBoxObject.cpp
layout/xul/nsIEditorBoxObject.idl
layout/xul/nsIIFrameBoxObject.idl
layout/xul/nsIPopupBoxObject.idl
layout/xul/nsListBoxObject.cpp
layout/xul/nsMenuBoxObject.cpp
layout/xul/nsPopupBoxObject.cpp
layout/xul/nsScrollBoxObject.cpp
layout/xul/tree/nsTreeBoxObject.cpp
layout/xul/tree/nsTreeBoxObject.h
tools/performance/layout/40-url-dup.txt
tools/performance/layout/40-url.txt
tools/performance/layout/Averagetable2.pl
tools/performance/layout/Footer.pl
tools/performance/layout/Header.pl
tools/performance/layout/collect.pl
tools/performance/layout/genfromlogs.pl
tools/performance/layout/history.pl
tools/performance/layout/history.txt
tools/performance/layout/perf-doc.html
tools/performance/layout/perf.pl
tools/performance/layout/property.inc
tools/performance/layout/property.t
tools/performance/layout/readme.txt
tools/performance/layout/tables/013100.html
tools/performance/layout/tables/021300.html
tools/performance/layout/tables/Daily-0317-TrendTable.html
tools/performance/layout/tables/Daily-0317.html
tools/performance/layout/tables/Daily_021700-TrendTable.html
tools/performance/layout/tables/Daily_021700-mozilla.html
tools/performance/layout/tables/Daily_021700.html
tools/performance/layout/tables/Daily_022500.html
tools/performance/layout/tables/Daily_0302.html
tools/performance/layout/tables/Daily_0308-TrendTable.html
tools/performance/layout/tables/Daily_0308.html
tools/performance/layout/tables/Daily_0324.html
tools/performance/layout/tables/M13.html
tools/performance/layout/uncombine.pl
tools/reorder/Makefile
tools/reorder/addrs2text.cpp
tools/reorder/cygprof.c
tools/reorder/elf_symbol_table.cpp
tools/reorder/elf_symbol_table.h
tools/reorder/elf_utils.cpp
tools/reorder/elf_utils.h
tools/reorder/func-by-addr.sh
tools/reorder/garope.cpp
tools/reorder/grope.cpp
tools/reorder/histogram.cpp
tools/reorder/interval_map.h
tools/reorder/mapaddrs.cpp
tools/reorder/mcount.c
tools/reorder/missing-syms.pl
tools/reorder/mult.c
tools/reorder/rseed.c
tools/reorder/syms-by-addr.sh
tools/reorder/test.cpp
tools/tests/ctor-dtor.pl
tools/tests/isa-module.pl
tools/uuiddeps/uuidgrep.bash
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -52,17 +52,17 @@ nsCoreUtils::HasClickListener(nsIContent
     (listenerManager->HasListenersFor(nsGkAtoms::onclick) ||
      listenerManager->HasListenersFor(nsGkAtoms::onmousedown) ||
      listenerManager->HasListenersFor(nsGkAtoms::onmouseup));
 }
 
 void
 nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
                                 int32_t aRowIndex, nsITreeColumn *aColumn,
-                                const nsCString& aPseudoElt)
+                                const nsAString& aPseudoElt)
 {
   nsCOMPtr<nsIDOMElement> tcElm;
   aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
   if (!tcElm)
     return;
 
   nsCOMPtr<nsIContent> tcContent(do_QueryInterface(tcElm));
   nsIDocument *document = tcContent->GetCurrentDoc();
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -39,17 +39,17 @@ public:
    * @param  aTreeBoxObj  [in] tree box object
    * @param  aRowIndex    [in] row index
    * @param  aColumn      [in] column object
    * @param  aPseudoElm   [in] pseudo elemenet inside the cell, see
    *                       nsITreeBoxObject for available values
    */
   static void DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
                                  int32_t aRowIndex, nsITreeColumn *aColumn,
-                                 const nsCString& aPseudoElt = EmptyCString());
+                                 const nsAString& aPseudoElt = EmptyString());
 
   /**
    * Send mouse event to the given element.
    *
    * @param aEventType   [in] an event type (see BasicEvents.h for constants)
    * @param aX           [in] x coordinate in dev pixels
    * @param aY           [in] y coordinate in dev pixels
    * @param aContent     [in] the element
@@ -309,9 +309,8 @@ public:
   static bool IsWhitespace(char16_t aChar)
   {
     return aChar == ' ' || aChar == '\n' ||
       aChar == '\r' || aChar == '\t' || aChar == 0xa0;
   }
 };
 
 #endif
-
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -15,16 +15,18 @@ this.EXPORTED_SYMBOLS = ['AccessFu']; //
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 
 const ACCESSFU_DISABLE = 0; // jshint ignore:line
 const ACCESSFU_ENABLE = 1;
 const ACCESSFU_AUTO = 2;
 
 const SCREENREADER_SETTING = 'accessibility.screenreader';
+const QUICKNAV_MODES_PREF = 'accessibility.accessfu.quicknav_modes';
+const QUICKNAV_INDEX_PREF = 'accessibility.accessfu.quicknav_index';
 
 this.AccessFu = { // jshint ignore:line
   /**
    * Initialize chrome-layer accessibility functionality.
    * If accessibility is enabled on the platform, then a special accessibility
    * mode is started.
    */
   attach: function attach(aWindow) {
@@ -98,21 +100,28 @@ this.AccessFu = { // jshint ignore:line
     let stylesheet = Utils.win.document.createProcessingInstruction(
       'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"');
     Utils.win.document.insertBefore(stylesheet, Utils.win.document.firstChild);
     this.stylesheet = Cu.getWeakReference(stylesheet);
 
 
     // Populate quicknav modes
     this._quicknavModesPref =
-      new PrefCache(
-        'accessibility.accessfu.quicknav_modes',
-        (aName, aValue) => {
-          this.Input.quickNavMode.updateModes(aValue);
-        }, true);
+      new PrefCache(QUICKNAV_MODES_PREF, (aName, aValue, aFirstRun) => {
+        this.Input.quickNavMode.updateModes(aValue);
+        if (!aFirstRun) {
+          // If the modes change, reset the current mode index to 0.
+          Services.prefs.setIntPref(QUICKNAV_INDEX_PREF, 0);
+        }
+      }, true);
+
+    this._quicknavCurrentModePref =
+      new PrefCache(QUICKNAV_INDEX_PREF, (aName, aValue) => {
+        this.Input.quickNavMode.updateCurrentMode(Number(aValue));
+      }, true);
 
     // Check for output notification
     this._notifyOutputPref =
       new PrefCache('accessibility.accessfu.notify_output');
 
 
     this.Input.start();
     Output.start();
@@ -662,27 +671,31 @@ var Input = {
           aGesture.touches[0].y);
         break;
       case 'doubletap1':
         this.activateCurrent();
         break;
       case 'taphold1':
         this.sendContextMenuMessage();
         break;
+      case 'doubletaphold1':
+        Utils.dispatchChromeEvent('accessibility-control', 'quicknav-menu');
+        break;
       case 'swiperight1':
         this.moveCursor('moveNext', 'Simple', 'gestures');
         break;
       case 'swipeleft1':
         this.moveCursor('movePrevious', 'Simple', 'gesture');
         break;
       case 'swipeup1':
-        this.contextAction('backward');
+        this.moveCursor(
+          'movePrevious', this.quickNavMode.current, 'gesture', true);
         break;
       case 'swipedown1':
-        this.contextAction('forward');
+        this.moveCursor('moveNext', this.quickNavMode.current, 'gesture', true);
         break;
       case 'exploreend1':
       case 'dwellend1':
         this.activateCurrent(null, true);
         break;
       case 'swiperight2':
         if (aGesture.edge) {
           Utils.dispatchChromeEvent('accessibility-control',
@@ -824,27 +837,22 @@ var Input = {
         {rule: aRule, x: aX, y: aY, origin: 'top'});
     } else {
       let win = Utils.win;
       Utils.winUtils.sendMouseEvent('mousemove',
         aX - win.mozInnerScreenX, aY - win.mozInnerScreenY, 0, 0, 0);
     }
   },
 
-  moveCursor: function moveCursor(aAction, aRule, aInputType) {
+  moveCursor: function moveCursor(aAction, aRule, aInputType, aAdjustRange) {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
     mm.sendAsyncMessage('AccessFu:MoveCursor',
-                        {action: aAction, rule: aRule,
-                         origin: 'top', inputType: aInputType});
-  },
-
-  contextAction: function contextAction(aDirection) {
-    // XXX: For now, the only supported context action is adjusting a range.
-    let mm = Utils.getMessageManager(Utils.CurrentBrowser);
-    mm.sendAsyncMessage('AccessFu:AdjustRange', {direction: aDirection});
+                        { action: aAction, rule: aRule,
+                          origin: 'top', inputType: aInputType,
+                          adjustRange: aAdjustRange });
   },
 
   moveByGranularity: function moveByGranularity(aDetails) {
     const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
 
     if (!this.editState.editing) {
       if (aDetails.granularity === MOVEMENT_GRANULARITY_PARAGRAPH) {
         this.moveCursor('move' + aDetails.direction, 'Paragraph', 'gesture');
@@ -952,31 +960,34 @@ var Input = {
   },
 
   quickNavMode: {
     get current() {
       return this.modes[this._currentIndex];
     },
 
     previous: function quickNavMode_previous() {
-      if (--this._currentIndex < 0) {
-        this._currentIndex = this.modes.length - 1;
-      }
+      Services.prefs.setIntPref(QUICKNAV_INDEX_PREF,
+        this._currentIndex > 0 ?
+          this._currentIndex - 1 : this.modes.length - 1);
     },
 
     next: function quickNavMode_next() {
-      if (++this._currentIndex >= this.modes.length) {
-        this._currentIndex = 0;
-      }
+      Services.prefs.setIntPref(QUICKNAV_INDEX_PREF,
+        this._currentIndex + 1 >= this.modes.length ?
+          0 : this._currentIndex + 1);
     },
 
     updateModes: function updateModes(aModes) {
       if (aModes) {
         this.modes = aModes.split(',');
       } else {
         this.modes = [];
       }
     },
 
-    _currentIndex: -1
+    updateCurrentMode: function updateCurrentMode(aModeIndex) {
+      Logger.debug('Quicknav mode:', this.modes[aModeIndex]);
+      this._currentIndex = aModeIndex;
+    }
   }
 };
 AccessFu.Input = Input;
--- a/accessible/jsat/ContentControl.jsm
+++ b/accessible/jsat/ContentControl.jsm
@@ -89,23 +89,28 @@ this.ContentControl.prototype = {
       Logger.logException(
         x, 'Error handling message: ' + JSON.stringify(aMessage.json));
     }
   },
 
   handleMoveCursor: function cc_handleMoveCursor(aMessage) {
     let origin = aMessage.json.origin;
     let action = aMessage.json.action;
+    let adjustRange = aMessage.json.adjustRange;
     let vc = this.vc;
 
     if (origin != 'child' && this.sendToChild(vc, aMessage)) {
       // Forwarded succesfully to child cursor.
       return;
     }
 
+    if (adjustRange && this.adjustRange(vc.position, action === 'moveNext')) {
+      return;
+    }
+
     let moved = vc[action](TraversalRules[aMessage.json.rule]);
 
     if (moved) {
       if (origin === 'child') {
         // We just stepped out of a child, clear child cursor.
         Utils.getMessageManager(aMessage.target).sendAsyncMessage(
           'AccessFu:ClearCursor', {});
       } else {
@@ -117,20 +122,24 @@ this.ContentControl.prototype = {
         } else if (action === 'movePrevious') {
           childAction = 'moveLast';
         }
 
         // Attempt to forward move to a potential child cursor in our
         // new position.
         this.sendToChild(vc, aMessage, { action: childAction }, true);
       }
-    } else if (!this._childMessageSenders.has(aMessage.target)) {
-      // We failed to move, and the message is not from a child, so forward
-      // to parent.
+    } else if (!this._childMessageSenders.has(aMessage.target) &&
+               origin !== 'top') {
+      // We failed to move, and the message is not from a parent, so forward
+      // to it.
       this.sendToParent(aMessage);
+    } else {
+      this._contentScope.get().sendAsyncMessage('AccessFu:Present',
+        Presentation.noMove(action));
     }
   },
 
   handleEvent: function cc_handleEvent(aEvent) {
     if (aEvent.type === 'mousemove') {
       this.handleMoveToPoint(
         { json: { x: aEvent.screenX, y: aEvent.screenY, rule: 'Simple' } });
     }
@@ -164,17 +173,17 @@ this.ContentControl.prototype = {
 
   handleActivate: function cc_handleActivate(aMessage) {
     let activateAccessible = (aAccessible) => {
       Logger.debug(() => {
         return ['activateAccessible', Logger.accessibleToString(aAccessible)];
       });
       try {
         if (aMessage.json.activateIfKey &&
-          aAccessible.role != Roles.KEY) {
+          !Utils.isActivatableOnFingerUp(aAccessible)) {
           // Only activate keys, don't do anything on other objects.
           return;
         }
       } catch (e) {
         // accessible is invalid. Silently fail.
         return;
       }
 
@@ -205,17 +214,17 @@ this.ContentControl.prototype = {
         for (let eventType of ['mousedown', 'mouseup']) {
           let evt = this.document.createEvent('MouseEvents');
           evt.initMouseEvent(eventType, true, true, this.window,
             x, y, 0, 0, 0, false, false, false, false, 0, null);
           node.dispatchEvent(evt);
         }
       }
 
-      if (aAccessible.role !== Roles.KEY) {
+      if (!Utils.isActivatableOnFingerUp(aAccessible)) {
         // Keys will typically have a sound of their own.
         this._contentScope.get().sendAsyncMessage('AccessFu:Present',
           Presentation.actionInvoked(aAccessible, 'click'));
       }
     };
 
     let focusedAcc = Utils.AccRetrieval.getAccessibleFor(
       this.document.activeElement);
@@ -252,16 +261,47 @@ this.ContentControl.prototype = {
 
     let vc = this.vc;
     if (!this.sendToChild(vc, aMessage, null, true)) {
       let position = vc.position;
       activateAccessible(getActivatableDescendant(position) || position);
     }
   },
 
+  adjustRange: function cc_adjustRange(aAccessible, aStepUp) {
+    let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible;
+    try {
+      acc.QueryInterface(Ci.nsIAccessibleValue);
+    } catch (x) {
+      // This is not an adjustable, return false.
+      return false;
+    }
+
+    let elem = acc.DOMNode;
+    if (!elem) {
+      return false;
+    }
+
+    if (elem.tagName === 'INPUT' && elem.type === 'range') {
+      elem[aStepUp ? 'stepDown' : 'stepUp']();
+      let evt = this.document.createEvent('UIEvent');
+      evt.initEvent('change', true, true);
+      elem.dispatchEvent(evt);
+    } else {
+      let evt = this.document.createEvent('KeyboardEvent');
+      let keycode = aStepUp ? content.KeyEvent.DOM_VK_DOWN :
+        content.KeyEvent.DOM_VK_UP;
+      evt.initKeyEvent(
+        "keypress", false, true, null, false, false, false, false, keycode, 0);
+      elem.dispatchEvent(evt);
+    }
+
+    return true;
+  },
+
   handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
     // XXX: Add sendToChild. Right now this is only used in Android, so no need.
     let direction = aMessage.json.direction;
     let granularity;
 
     switch(aMessage.json.granularity) {
       case MOVEMENT_GRANULARITY_CHARACTER:
         granularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -112,16 +112,21 @@ Presenter.prototype = {
   editingModeChanged: function editingModeChanged(aIsEditing) {}, // jshint ignore:line
 
   /**
    * Announce something. Typically an app state change.
    */
   announce: function announce(aAnnouncement) {}, // jshint ignore:line
 
 
+  /**
+   * User tried to move cursor forward or backward with no success.
+   * @param {string} aMoveMethod move method that was used (eg. 'moveNext').
+   */
+  noMove: function noMove(aMoveMethod) {},
 
   /**
    * Announce a live region.
    * @param  {PivotContext} aContext context object for an accessible.
    * @param  {boolean} aIsPolite A politeness level for a live region.
    * @param  {boolean} aIsHide An indicator of hide/remove event.
    * @param  {string} aModifiedText Optional modified text.
    */
@@ -477,17 +482,17 @@ B2GPresenter.prototype.pivotChanged =
 
     return {
       type: this.type,
       details: {
         eventType: 'vc-change',
         data: UtteranceGenerator.genForContext(aContext),
         options: {
           pattern: this.PIVOT_CHANGE_HAPTIC_PATTERN,
-          isKey: aContext.accessible.role === Roles.KEY,
+          isKey: Utils.isActivatableOnFingerUp(aContext.accessible),
           reason: this.pivotChangedReasons[aReason],
           isUserInput: aIsUserInput
         }
       }
     };
   };
 
 B2GPresenter.prototype.valueChanged =
@@ -531,16 +536,27 @@ B2GPresenter.prototype.announce =
       type: this.type,
       details: {
         eventType: 'announcement',
         data: aAnnouncement
       }
     };
   };
 
+B2GPresenter.prototype.noMove =
+  function B2GPresenter_noMove(aMoveMethod) {
+    return {
+      type: this.type,
+      details: {
+        eventType: 'no-move',
+        data: aMoveMethod
+      }
+    };
+  };
+
 /**
  * A braille presenter
  */
 function BraillePresenter() {}
 
 BraillePresenter.prototype = Object.create(Presenter.prototype);
 
 BraillePresenter.prototype.type = 'Braille';
@@ -631,16 +647,20 @@ this.Presentation = { // jshint ignore:l
 
   announce: function Presentation_announce(aAnnouncement) {
     // XXX: Typically each presenter uses the UtteranceGenerator,
     // but there really isn't a point here.
     return [p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)) // jshint ignore:line
       for each (p in this.presenters)]; // jshint ignore:line
   },
 
+  noMove: function Presentation_noMove(aMoveMethod) {
+    return [p.noMove(aMoveMethod) for each (p in this.presenters)]; // jshint ignore:line
+  },
+
   liveRegion: function Presentation_liveRegion(aAccessible, aIsPolite, aIsHide,
     aModifiedText) {
     let context;
     if (!aModifiedText) {
       context = new PivotContext(aAccessible, null, -1, -1, true,
         aIsHide ? true : false);
     }
     return [p.liveRegion(context, aIsPolite, aIsHide, aModifiedText) // jshint ignore:line
--- a/accessible/jsat/TraversalRules.jsm
+++ b/accessible/jsat/TraversalRules.jsm
@@ -29,16 +29,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
 
 function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter) {
   this._explicitMatchRoles = new Set(aRoles);
   this._matchRoles = aRoles;
   if (aRoles.indexOf(Roles.LABEL) < 0) {
     this._matchRoles.push(Roles.LABEL);
   }
+  if (aRoles.indexOf(Roles.INTERNAL_FRAME) < 0) {
+    // Used for traversing in to child OOP frames.
+    this._matchRoles.push(Roles.INTERNAL_FRAME);
+  }
   this._matchFunc = aMatchFunc || function() { return Filters.MATCH; };
   this.preFilter = aPreFilter || gSimplePreFilter;
 }
 
 BaseTraversalRule.prototype = {
     getMatchRoles: function BaseTraversalRule_getmatchRoles(aRules) {
       aRules.value = this._matchRoles;
       return aRules.value.length;
@@ -93,19 +97,17 @@ var gSimpleTraversalRoles =
    Roles.HEADER,
    Roles.HEADING,
    Roles.SLIDER,
    Roles.SPINBUTTON,
    Roles.OPTION,
    Roles.LISTITEM,
    Roles.GRID_CELL,
    Roles.COLUMNHEADER,
-   Roles.ROWHEADER,
-   // Used for traversing in to child OOP frames.
-   Roles.INTERNAL_FRAME];
+   Roles.ROWHEADER];
 
 var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
   // An object is simple, if it either has a single child lineage,
   // or has a flat subtree.
   function isSingleLineage(acc) {
     for (let child = acc; child; child = child.firstChild) {
       if (Utils.visibleChildCount(child) > 1) {
         return false;
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -465,16 +465,24 @@ this.Utils = { // jshint ignore:line
       // emulator add-on.
       window.dispatchEvent(new window.CustomEvent(aType, {
         bubbles: true,
         cancelable: true,
         detail: details
       }));
     }
 
+  },
+
+  isActivatableOnFingerUp: function isActivatableOnFingerUp(aAccessible) {
+    if (aAccessible.role === Roles.KEY) {
+      return true;
+    }
+    let quick_activate = this.getAttributes(aAccessible)['moz-quick-activate'];
+    return quick_activate && JSON.parse(quick_activate);
   }
 };
 
 /**
  * State object used internally to process accessible's states.
  * @param {Number} aBase     Base state.
  * @param {Number} aExtended Extended state.
  */
@@ -944,17 +952,17 @@ this.PrefCache = function PrefCache(aNam
   this.name = aName;
   this.callback = aCallback;
 
   let branch = Services.prefs;
   this.value = this._getValue(branch);
 
   if (this.callback && aRunCallbackNow) {
     try {
-      this.callback(this.name, this.value);
+      this.callback(this.name, this.value, true);
     } catch (x) {
       Logger.logException(x);
     }
   }
 
   branch.addObserver(aName, this, true);
 };
 
@@ -977,19 +985,20 @@ PrefCache.prototype = {
     } catch (x) {
       // Pref does not exist.
       return null;
     }
   },
 
   observe: function observe(aSubject) {
     this.value = this._getValue(aSubject.QueryInterface(Ci.nsIPrefBranch));
+    Logger.info('pref changed', this.name, this.value);
     if (this.callback) {
       try {
-        this.callback(this.name, this.value);
+        this.callback(this.name, this.value, false);
       } catch (x) {
         Logger.logException(x);
       }
     }
   },
 
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
                                           Ci.nsISupportsWeakReference])
--- a/accessible/jsat/content-script.js
+++ b/accessible/jsat/content-script.js
@@ -87,56 +87,29 @@ function scroll(aMessage) {
   if (!forwardToChild(aMessage, scroll, position)) {
     sendAsyncMessage('AccessFu:DoScroll',
                      { bounds: Utils.getBounds(position, true),
                        page: aMessage.json.page,
                        horizontal: aMessage.json.horizontal });
   }
 }
 
-function adjustRange(aMessage) {
-  function sendUpDownKey(aAccessible) {
-    let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible;
-    let elem = acc.DOMNode;
-    if (elem) {
-      if (elem.tagName === 'INPUT' && elem.type === 'range') {
-        elem[aMessage.json.direction === 'forward' ? 'stepDown' : 'stepUp']();
-        let changeEvent = content.document.createEvent('UIEvent');
-        changeEvent.initEvent('change', true, true);
-        elem.dispatchEvent(changeEvent);
-      } else {
-        let evt = content.document.createEvent('KeyboardEvent');
-        let keycode = aMessage.json.direction == 'forward' ?
-              content.KeyEvent.DOM_VK_DOWN : content.KeyEvent.DOM_VK_UP;
-        evt.initKeyEvent(
-          "keypress", false, true, null, false, false, false, false, keycode, 0);
-        elem.dispatchEvent(evt);
-      }
-    }
-  }
-
-  let position = Utils.getVirtualCursor(content.document).position;
-  if (!forwardToChild(aMessage, adjustRange, position)) {
-    sendUpDownKey(position);
-  }
-}
 addMessageListener(
   'AccessFu:Start',
   function(m) {
     if (m.json.logLevel) {
       Logger.logLevel = Logger[m.json.logLevel];
     }
 
     Logger.debug('AccessFu:Start');
     if (m.json.buildApp)
       Utils.MozBuildApp = m.json.buildApp;
 
     addMessageListener('AccessFu:ContextMenu', activateContextMenu);
     addMessageListener('AccessFu:Scroll', scroll);
-    addMessageListener('AccessFu:AdjustRange', adjustRange);
 
     if (!contentControl) {
       contentControl = new ContentControl(this);
     }
     contentControl.start();
 
     if (!eventManager) {
       eventManager = new EventManager(this, contentControl);
--- a/accessible/tests/mochitest/actions/test_treegrid.xul
+++ b/accessible/tests/mochitest/actions/test_treegrid.xul
@@ -150,18 +150,17 @@
     {
       var treeNode = getNode("tabletree");
       waitForEvent(EVENT_REORDER, treeNode, doTestActions);
       treeNode.view = new nsTreeTreeView();
     }
 
     function test1()
     {
-      var boxObj = getNode("tabletree").treeBoxObject;
-      boxObj.view.setCellValue(0, boxObj.columns.firstColumn, "false");
+      getNode("tabletree").view.setCellValue(0, boxObj.columns.firstColumn, "false");
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
   <hbox flex="1" style="overflow: auto;">
@@ -191,9 +190,8 @@
       </tree>
 
       <vbox id="debug"/>
       <button oncommand="test1();" label="uncheck"/>
     </vbox>
   </hbox>
 
 </window>
-
--- a/accessible/tests/mochitest/hittest/test_zoom_tree.xul
+++ b/accessible/tests/mochitest/hittest/test_zoom_tree.xul
@@ -35,26 +35,24 @@
       var treecol1 = tabDocument.getElementById("treecol1");
 
       // tree columns
       hitTest(tree, treecols, treecol1);
 
       // tree rows and cells
       var treeBoxObject = tree.treeBoxObject;
       var treeBodyBoxObj = tree.treeBoxObject.treeBody.boxObject;
-      var xObj = {}, yObj = {}, widthObj = {}, heightObj = {};
-      treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell",
-                                         xObj, yObj, widthObj, heightObj);
+      var rect = treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell");
 
       var treeAcc = getAccessible(tree, [nsIAccessibleTable]);
       var cellAcc = treeAcc.getCellAt(1, 0);
       var rowAcc = cellAcc.parent;
 
-      var cssX = xObj.value + treeBodyBoxObj.x;
-      var cssY = yObj.value + treeBodyBoxObj.y;
+      var cssX = rect.x + treeBodyBoxObj.x;
+      var cssY = rect.y + treeBodyBoxObj.y;
       var [x, y] = CSSToDevicePixels(tabWindow, cssX, cssY);
 
       testChildAtPoint(treeAcc, x, y, rowAcc, cellAcc);
       testChildAtPoint(rowAcc, x, y, cellAcc, cellAcc);
 
       // do zoom
       zoomDocument(tabDocument, 1.5);
 
@@ -95,9 +93,8 @@
       <div id="content" style="display: none">
       </div>
       <pre id="test">
       </pre>
     </body>
   </hbox>
 
 </window>
-
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -13,11 +13,12 @@ support-files =
 skip-if = buildapp == 'mulet'
 [test_content_text.html]
 skip-if = buildapp == 'mulet'
 [test_explicit_names.html]
 [test_gesture_tracker.html]
 [test_landmarks.html]
 [test_live_regions.html]
 [test_output.html]
+[test_quicknav_modes.html]
 [test_tables.html]
 [test_pointer_relay.html]
 [test_traversal.html]
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -130,17 +130,17 @@ var AccessFuTest = {
     } catch (ex) {
       // StopIteration exception.
       this.finish();
       return;
     }
     testFunc();
   },
 
-  runTests: function AccessFuTest_runTests() {
+  runTests: function AccessFuTest_runTests(aAdditionalPrefs) {
     if (gTestFuncs.length === 0) {
       ok(false, "No tests specified!");
       SimpleTest.finish();
       return;
     }
 
     // Create an Iterator for gTestFuncs array.
     gIterator = Iterator(gTestFuncs); // jshint ignore:line
@@ -151,20 +151,21 @@ var AccessFuTest = {
     AccessFu.attach(getMainChromeWindow(window));
 
     AccessFu.readyCallback = function readyCallback() {
       // Enable logging to the console service.
       Logger.test = true;
       Logger.logLevel = Logger.DEBUG;
     };
 
-    SpecialPowers.pushPrefEnv({
-      'set': [['accessibility.accessfu.notify_output', 1],
-              ['dom.mozSettings.enabled', true]]
-    }, function () {
+    var prefs = [['accessibility.accessfu.notify_output', 1],
+      ['dom.mozSettings.enabled', true]];
+    prefs.push.apply(prefs, aAdditionalPrefs);
+
+    SpecialPowers.pushPrefEnv({ 'set': prefs }, function () {
       if (AccessFuTest._waitForExplicitFinish) {
         // Run all test functions asynchronously.
         AccessFuTest.nextTest();
       } else {
         // Run all test functions synchronously.
         [testFunc() for (testFunc of gTestFuncs)]; // jshint ignore:line
         AccessFuTest.finish();
       }
@@ -359,29 +360,39 @@ var ContentMessages = {
 
   clearCursor: {
     name: 'AccessFu:ClearCursor',
     json: {
       origin: 'top'
     }
   },
 
-  adjustRangeUp: {
-    name: 'AccessFu:AdjustRange',
-    json: {
-      origin: 'top',
-      direction: 'backward'
+  moveOrAdjustUp: function moveOrAdjustUp(aRule) {
+    return {
+      name: 'AccessFu:MoveCursor',
+      json: {
+        origin: 'top',
+        action: 'movePrevious',
+        inputType: 'gesture',
+        rule: (aRule || 'Simple'),
+        adjustRange: true
+      }
     }
   },
 
-  adjustRangeDown: {
-    name: 'AccessFu:AdjustRange',
-    json: {
-      origin: 'top',
-      direction: 'forward'
+  moveOrAdjustDown: function moveOrAdjustUp(aRule) {
+    return {
+      name: 'AccessFu:MoveCursor',
+      json: {
+        origin: 'top',
+        action: 'moveNext',
+        inputType: 'gesture',
+        rule: (aRule || 'Simple'),
+        adjustRange: true
+      }
     }
   },
 
   focusSelector: function focusSelector(aSelector, aBlur) {
     return {
       name: 'AccessFuTest:Focus',
       json: {
         selector: aSelector,
@@ -649,16 +660,22 @@ function ExpectedAnnouncement(aAnnouncem
     eventType: AndroidEvent.ANNOUNCEMENT,
     text: [ aAnnouncement],
     addedCount: aAnnouncement.length
   }], aOptions);
 }
 
 ExpectedAnnouncement.prototype = Object.create(ExpectedPresent.prototype);
 
+function ExpectedNoMove(aOptions) {
+  ExpectedPresent.call(this, {eventType: 'no-move' }, null, aOptions);
+}
+
+ExpectedNoMove.prototype = Object.create(ExpectedPresent.prototype);
+
 var AndroidEvent = {
   VIEW_CLICKED: 0x01,
   VIEW_LONG_CLICKED: 0x02,
   VIEW_SELECTED: 0x04,
   VIEW_FOCUSED: 0x08,
   VIEW_TEXT_CHANGED: 0x10,
   WINDOW_STATE_CHANGED: 0x20,
   VIEW_HOVER_ENTER: 0x80,
--- a/accessible/tests/mochitest/jsat/test_content_integration.html
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -29,16 +29,17 @@
       iframe.addEventListener('mozbrowserloadend', function () {
       var contentTest = new AccessFuContentTest(
         [
           // Simple traversal forward
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(
             ['Phone status bar', 'Traversal Rule test document'],
             { focused: 'body' })],
+          [ContentMessages.simpleMovePrevious, new ExpectedNoMove()],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.simpleMoveNext, new ExpectedCursorChange(
             ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'],
             { focused: 'iframe' })],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'},
             {'string': 'checkbutton'}, {'string': 'listStart'},
@@ -47,24 +48,24 @@
           // check checkbox
           [ContentMessages.activateCurrent(),
            new ExpectedClickAction({ no_android: true }),
            new ExpectedCheckAction(true, { android_todo: true })],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['much range', {'string': 'label'}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])],
-          [ContentMessages.adjustRangeUp, new ExpectedValueChange('6')],
+          [ContentMessages.moveOrAdjustUp(), new ExpectedValueChange('6')],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
 
           // Simple traversal backward
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(['much range', '6', {'string': 'slider'}, 'such app'])],
-          [ContentMessages.adjustRangeDown, new ExpectedValueChange('5')],
+          [ContentMessages.moveOrAdjustDown(), new ExpectedValueChange('5')],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(['much range', {'string': 'label'}])],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(['many option', {'string': 'stateChecked'},
             {'string': 'checkbutton'}, {'string': 'listStart'},
             {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])],
           // uncheck checkbox
           [ContentMessages.activateCurrent(),
@@ -86,16 +87,42 @@
             ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
           // Move from an inner frame to the last element in the parent doc
           [ContentMessages.simpleMoveLast,
             new ExpectedCursorChange(
               ['Home', {'string': 'pushbutton'}], { b2g_todo: true })],
 
           [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
 
+          [ContentMessages.simpleMoveNext,
+           new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
+          [ContentMessages.moveOrAdjustDown('FormElement'),
+           new ExpectedCursorChange(['Back', {"string": "pushbutton"}])],
+          [ContentMessages.moveOrAdjustDown('FormElement'),
+           new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'},
+            {'string': 'checkbutton'}, {'string': 'listStart'},
+            {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}, 'such app'])],
+          [ContentMessages.moveOrAdjustDown('FormElement'),
+           new ExpectedCursorChange(['much range', '5', {'string': 'slider'}])],
+          // Calling AdjustOrMove should adjust the range.
+          [ContentMessages.moveOrAdjustDown('FormElement'),
+           new ExpectedValueChange('4')],
+          [ContentMessages.moveOrAdjustUp('FormElement'),
+           new ExpectedValueChange('5')],
+          [ContentMessages.simpleMovePrevious,
+           new ExpectedCursorChange(['much range', {'string': 'label'}])],
+          [ContentMessages.moveOrAdjustUp('FormElement'),
+           new ExpectedCursorChange(['many option', {'string': 'stateNotChecked'},
+            {'string': 'checkbutton'}, {'string': 'listStart'},
+            {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}])],
+          [ContentMessages.moveOrAdjustUp('FormElement'),
+           new ExpectedCursorChange(['Back', {"string": "pushbutton"}])],
+
+          [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
+
           // Moving to the absolute first item from an embedded document
           // fails. Bug 972035.
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
@@ -220,17 +247,18 @@
           [doc.defaultView.showAlert,
            new ExpectedCursorChange(['This is an alert!',
             {'string': 'headingLevel', 'args': [1]}, {'string': 'dialog'}])],
 
           [function hideAlertAndFocusHomeButton() {
             doc.defaultView.hideAlert();
             doc.querySelector('button#home').focus();
           }, new ExpectedCursorChange(['Home', {'string': 'pushbutton'},
-            'Traversal Rule test document'])]
+            'Traversal Rule test document'])],
+          [ContentMessages.simpleMoveNext, new ExpectedNoMove()]
         ]);
 
         addA11yLoadEvent(function() {
           contentTest.start(function () {
             closeBrowserWindow();
             SimpleTest.finish();
           });
         }, doc.defaultView)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html
@@ -0,0 +1,103 @@
+<html>
+
+<head>
+  <title>AccessFu test for enabling</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="./jsatcommon.js"></script>
+  <script type="application/javascript">
+
+    function prefStart() {
+      // Start AccessFu via pref.
+      SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
+      AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
+    }
+
+    function nextMode(aCurrentMode, aNextMode) {
+      return function() {
+        is(AccessFu.Input.quickNavMode.current, aCurrentMode,
+          'initial current mode is correct');
+        AccessFu.Input.quickNavMode.next();
+        _expectMode(aNextMode, AccessFuTest.nextTest);
+      }
+    }
+
+    function prevMode(aCurrentMode, aNextMode) {
+      return function() {
+        is(AccessFu.Input.quickNavMode.current, aCurrentMode,
+          'initial current mode is correct');
+        AccessFu.Input.quickNavMode.previous();
+        _expectMode(aNextMode, AccessFuTest.nextTest);
+      }
+    }
+
+    function setMode(aModeIndex, aExpectedMode) {
+      return function() {
+        SpecialPowers.setIntPref(
+          'accessibility.accessfu.quicknav_index', aModeIndex);
+        _expectMode(aExpectedMode, AccessFuTest.nextTest);
+      }
+    }
+
+    function reconfigureModes() {
+      SpecialPowers.setCharPref('accessibility.accessfu.quicknav_modes',
+        'Landmark,Button,Entry,Graphic');
+      // When the modes are reconfigured, the current mode should
+      // be set to the first in the new list.
+      _expectMode('Landmark', AccessFuTest.nextTest);
+    }
+
+    function _expectMode(aExpectedMode, aCallback) {
+      if (AccessFu.Input.quickNavMode.current === aExpectedMode) {
+        ok(true, 'correct mode');
+        aCallback();
+      } else {
+        AccessFuTest.once_log('Quicknav mode: ' + aExpectedMode, function() {
+          ok(true, 'correct mode');
+          aCallback();
+        });
+      }
+    }
+
+    // Listen for initial 'EventManager.start' and disable AccessFu.
+    function prefStop() {
+      ok(AccessFu._enabled, "AccessFu was started via preference.");
+      AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish);
+      SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
+    }
+
+    function doTest() {
+      AccessFuTest.addFunc(prefStart);
+      AccessFuTest.addFunc(nextMode('Link', 'Heading'));
+      AccessFuTest.addFunc(nextMode('Heading', 'FormElement'));
+      AccessFuTest.addFunc(nextMode('FormElement', 'Link'));
+      AccessFuTest.addFunc(nextMode('Link', 'Heading'));
+      AccessFuTest.addFunc(prevMode('Heading', 'Link'));
+      AccessFuTest.addFunc(prevMode('Link', 'FormElement'));
+      AccessFuTest.addFunc(setMode(1, 'Heading'));
+      AccessFuTest.addFunc(reconfigureModes);
+      AccessFuTest.addFunc(prefStop);
+      AccessFuTest.waitForExplicitFinish();
+      AccessFuTest.runTests([   // Will call SimpleTest.finish();
+        ['accessibility.accessfu.quicknav_modes', 'Link,Heading,FormElement']]);
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+
+</head>
+<body>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=811307"
+     title="[AccessFu] Add mochitest for enabling">
+    Mozilla Bug 811307
+  </a>
+</body>
+</html>
\ No newline at end of file
--- a/accessible/tests/mochitest/name/test_tree.xul
+++ b/accessible/tests/mochitest/name/test_tree.xul
@@ -27,17 +27,17 @@
   <script type="application/javascript">
   <![CDATA[
     function treeTester(aID)
     {
       this.DOMNode = getNode(aID);
 
       this.invoke = function treeTester_invoke()
       {
-        this.DOMNode.treeBoxObject.view = new nsTreeTreeView();
+        this.DOMNode.view = new nsTreeTreeView();
       }
 
       this.check = function treeTester_check(aEvent)
       {
         var tree = {
           role: ROLE_OUTLINE,
           children: [
             {
@@ -85,17 +85,17 @@
     }
 
     function tableTester(aID, aIsTable, aCol1ID, aCol2ID)
     {
       this.DOMNode = getNode(aID);
 
       this.invoke = function tableTester_invoke()
       {
-        this.DOMNode.treeBoxObject.view = new nsTableTreeView(2);
+        this.DOMNode.view = new nsTableTreeView(2);
       }
 
       this.check = function tableTester_check(aEvent)
       {
         var tree = {
           role: aIsTable ? ROLE_TABLE : ROLE_TREE_TABLE,
           children: [
             {
@@ -204,9 +204,8 @@
       <treecol id="tt_col2" flex="1" label="column 2"/>
     </treecols>
     <treechildren/>
   </tree>
 
   </vbox> <!-- close tests area -->
   </hbox> <!-- close main area -->
 </window>
-
--- a/accessible/tests/mochitest/selectable/test_tree.xul
+++ b/accessible/tests/mochitest/selectable/test_tree.xul
@@ -37,17 +37,17 @@
      * accessible.
      */
     function statesChecker(aTreeID, aView)
     {
       this.DOMNode = getNode(aTreeID);
       
       this.invoke = function invoke()
       {
-        this.DOMNode.treeBoxObject.view = aView;
+        this.DOMNode.view = aView;
       }
       this.check = function check()
       {
         var tree = getAccessible(this.DOMNode);
 
         var isTreeMultiSelectable = false;
         var seltype = this.DOMNode.getAttribute("seltype");
         if (seltype != "single" && seltype != "cell" && seltype != "text")
@@ -181,9 +181,8 @@
         <treechildren/>
       </tree>
 
       <vbox id="debug"/>
     </vbox>
   </hbox>
 
 </window>
-
--- a/accessible/tests/mochitest/states/test_tree.xul
+++ b/accessible/tests/mochitest/states/test_tree.xul
@@ -33,17 +33,17 @@
      * accessible.
      */
     function statesChecker(aTreeID, aView)
     {
       this.DOMNode = getNode(aTreeID);
 
       this.invoke = function statesChecker_invoke()
       {
-        this.DOMNode.treeBoxObject.view = aView;
+        this.DOMNode.view = aView;
       }
 
       this.check = function statesChecker_check()
       {
         var tree = getAccessible(this.DOMNode);
 
         // tree states
         testStates(tree, STATE_READONLY);
@@ -145,9 +145,8 @@
         <treechildren/>
       </tree>
 
       <vbox id="debug"/>
     </vbox>
   </hbox>
 
 </window>
-
--- a/accessible/tests/mochitest/tree/test_tree.xul
+++ b/accessible/tests/mochitest/tree/test_tree.xul
@@ -67,17 +67,17 @@
       var accTreeForTree = {
         role: aRole,
         children: [
           accTreeForColumns
         ]
       };
 
       var treeBoxObject = aTree.treeBoxObject;
-      var view = treeBoxObject.view;
+      var view = aTree.view;
       var columnCount = treeBoxObject.columns.count;
 
       for (var idx = 0; idx < columnCount; idx++)
         accTreeForColumns.children.push({ COLUMNHEADER: [ ] });
       if (!aTree.hasAttribute("hidecolumnpicker"))
         accTreeForColumns.children.push({ PUSHBUTTON: [ { MENUPOPUP: [] } ] });
 
       for (var idx = 0; idx < view.rowCount; idx++)
@@ -90,17 +90,17 @@
      * Event queue invoker object to test accessible tree for XUL tree element.
      */
     function treeChecker(aID, aView, aRole)
     {
       this.DOMNode = getNode(aID);
 
       this.invoke = function invoke()
       {
-        this.DOMNode.treeBoxObject.view = aView;
+        this.DOMNode.view = aView;
       }
       this.check = function check(aEvent)
       {
         testAccessibleTreeFor(this.DOMNode, aRole);
       }
       this.getID = function getID()
       {
         return "Tree testing of " + aID;
@@ -175,9 +175,8 @@
         <treechildren/>
       </tree>
 
       <vbox id="debug"/>
     </vbox>
   </hbox>
 
 </window>
-
--- a/accessible/tests/mochitest/treeview.js
+++ b/accessible/tests/mochitest/treeview.js
@@ -12,17 +12,17 @@ function loadXULTreeAndDoTest(aDoTestFun
     this.treeNode = getNode(aTreeID);
 
     this.eventSeq = [
       new invokerChecker(EVENT_REORDER, this.treeNode)
     ];
 
     this.invoke = function loadXULTree_invoke()
     {
-      this.treeNode.treeBoxObject.view = aTreeView;
+      this.treeNode.view = aTreeView;
     }
 
     this.getID = function loadXULTree_getID()
     {
       return "Load XUL tree " + prettyName(aTreeID);
     }
   }
 
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -194,17 +194,17 @@ XULTreeAccessible::ChildAtPoint(int32_t 
 
   nsIntRect rootRect = rootFrame->GetScreenRect();
 
   int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
   int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
 
   int32_t row = -1;
   nsCOMPtr<nsITreeColumn> column;
-  nsAutoCString childEltUnused;
+  nsAutoString childEltUnused;
   mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
                    childEltUnused);
 
   // If we failed to find tree cell for the given point then it might be
   // tree columns.
   if (row == -1 || !column)
     return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild);
 
@@ -741,17 +741,17 @@ XULTreeItemAccessibleBase::Bounds() cons
 
   nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
   if (!boxObj)
     return nsIntRect();
 
   nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
 
   int32_t x = 0, y = 0, width = 0, height = 0;
-  nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyCString(),
+  nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyString(),
                                             &x, &y, &width, &height);
   if (NS_FAILED(rv))
     return nsIntRect();
 
   boxObj->GetWidth(&width);
 
   int32_t tcX = 0, tcY = 0;
   boxObj->GetScreenX(&tcX);
@@ -991,25 +991,25 @@ XULTreeItemAccessibleBase::DispatchClick
 
   nsCOMPtr<nsITreeColumns> columns;
   mTree->GetColumns(getter_AddRefs(columns));
   if (!columns)
     return;
 
   // Get column and pseudo element.
   nsCOMPtr<nsITreeColumn> column;
-  nsAutoCString pseudoElm;
+  nsAutoString pseudoElm;
 
   if (aActionIndex == eAction_Click) {
     // Key column is visible and clickable.
     columns->GetKeyColumn(getter_AddRefs(column));
   } else {
     // Primary column contains a twisty we should click on.
     columns->GetPrimaryColumn(getter_AddRefs(column));
-    pseudoElm = NS_LITERAL_CSTRING("twisty");
+    pseudoElm = NS_LITERAL_STRING("twisty");
   }
 
   if (column)
     nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm);
 }
 
 Accessible*
 XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset,
@@ -1191,9 +1191,8 @@ XULTreeColumAccessible::GetSiblingAtOffs
         if (treeAcc)
           return treeAcc->GetTreeItemAccessible(aOffset - 1);
       }
     }
   }
 
   return nullptr;
 }
-
--- a/accessible/xul/XULTreeGridAccessible.cpp
+++ b/accessible/xul/XULTreeGridAccessible.cpp
@@ -336,17 +336,17 @@ XULTreeGridRowAccessible::ChildAtPoint(i
 
   nsIntRect rootRect = rootFrame->GetScreenRect();
 
   int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
   int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
 
   int32_t row = -1;
   nsCOMPtr<nsITreeColumn> column;
-  nsAutoCString childEltUnused;
+  nsAutoString childEltUnused;
   mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
                    childEltUnused);
 
   // Return if we failed to find tree cell in the row for the given point.
   if (row != mRow || !column)
     return nullptr;
 
   return GetCellAccessible(column);
@@ -517,17 +517,17 @@ XULTreeGridCellAccessible::Bounds() cons
   // Get bounds for tree cell and add x and y of treechildren element to
   // x and y of the cell.
   nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
   if (!boxObj)
     return nsIntRect();
 
   int32_t x = 0, y = 0, width = 0, height = 0;
   nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn,
-                                            NS_LITERAL_CSTRING("cell"),
+                                            NS_LITERAL_STRING("cell"),
                                             &x, &y, &width, &height);
   if (NS_FAILED(rv))
     return nsIntRect();
 
   int32_t tcX = 0, tcY = 0;
   boxObj->GetScreenX(&tcX);
   boxObj->GetScreenY(&tcY);
   x += tcX;
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -3,17 +3,16 @@ dnl Local autoconf macros used with mozi
 dnl The contents of this file are under the Public Domain.
 dnl
 
 builtin(include, build/autoconf/hotfixes.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/hooks.m4)dnl
 builtin(include, build/autoconf/config.status.m4)dnl
 builtin(include, build/autoconf/toolchain.m4)dnl
-builtin(include, build/autoconf/ccache.m4)dnl
 builtin(include, build/autoconf/wrapper.m4)dnl
 builtin(include, build/autoconf/nspr.m4)dnl
 builtin(include, build/autoconf/nspr-build.m4)dnl
 builtin(include, build/autoconf/nss.m4)dnl
 builtin(include, build/autoconf/pkg.m4)dnl
 builtin(include, build/autoconf/codeset.m4)dnl
 builtin(include, build/autoconf/altoptions.m4)dnl
 builtin(include, build/autoconf/mozprog.m4)dnl
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -789,16 +789,18 @@ pref("dom.ipc.systemMessageCPULockTimeou
 pref("dom.disable_window_open_dialog_feature", true);
 
 // Enable before keyboard events and after keyboard events.
 pref("dom.beforeAfterKeyboardEvent.enabled", true);
 
 // Screen reader support
 pref("accessibility.accessfu.activate", 2);
 pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem");
+// Active quicknav mode, index value of list from quicknav_modes
+pref("accessibility.accessfu.quicknav_index", 0);
 // Setting for an utterance order (0 - description first, 1 - description last).
 pref("accessibility.accessfu.utterance", 1);
 // Whether to skip images with empty alt text
 pref("accessibility.accessfu.skip_empty_images", true);
 
 // Enable hit-target fluffing
 pref("ui.touch.radius.enabled", true);
 pref("ui.touch.radius.leftmm", 3);
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -452,16 +452,26 @@ SettingsListener.observe("theme.selected
     Services.prefs.setCharPref('dom.mozApps.selected_theme', newTheme);
     Services.prefs.savePrefFile(null);
     Services.obs.notifyObservers(null, 'app-theme-changed', newTheme);
   }
 });
 
 // =================== Various simple mapping  ======================
 let settingsToObserve = {
+  'accessibility.screenreader_quicknav_modes': {
+    prefName: 'accessibility.accessfu.quicknav_modes',
+    resetToPref: true,
+    defaultValue: ''
+  },
+  'accessibility.screenreader_quicknav_index': {
+    prefName: 'accessibility.accessfu.quicknav_index',
+    resetToPref: true,
+    defaultValue: 0
+  },
   'app.update.channel': {
     resetToPref: true
   },
   'app.update.interval': 86400,
   'app.update.url': {
     resetToPref: true
   },
   'apz.force-enable': {
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -703,23 +703,22 @@ var BookmarksEventHandler = {
 
   fillInBHTooltip: function BEH_fillInBHTooltip(aDocument, aEvent) {
     var node;
     var cropped = false;
     var targetURI;
 
     if (aDocument.tooltipNode.localName == "treechildren") {
       var tree = aDocument.tooltipNode.parentNode;
-      var row = {}, column = {};
       var tbo = tree.treeBoxObject;
-      tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, column, {});
-      if (row.value == -1)
+      var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
+      if (cell.row == -1)
         return false;
-      node = tree.view.nodeForTreeIndex(row.value);
-      cropped = tbo.isCellCropped(row.value, column.value);
+      node = tree.view.nodeForTreeIndex(cell.row);
+      cropped = tbo.isCellCropped(cell.row, cell.col);
     }
     else {
       // Check whether the tooltipNode is a Places node.
       // In such a case use it, otherwise check for targetURI attribute.
       var tooltipNode = aDocument.tooltipNode;
       if (tooltipNode._placesNode)
         node = tooltipNode._placesNode;
       else {
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -503,17 +503,17 @@ function makeGeneralTab()
     metaGroup.collapsed = true;
   else {
     var metaTagsCaption = document.getElementById("metaTagsCaption");
     if (length == 1)
       metaTagsCaption.label = gBundle.getString("generalMetaTag");
     else
       metaTagsCaption.label = gBundle.getFormattedString("generalMetaTags", [length]);
     var metaTree = document.getElementById("metatree");
-    metaTree.treeBoxObject.view = gMetaView;
+    metaTree.view = gMetaView;
 
     for (var i = 0; i < length; i++)
       gMetaView.addRow([metaNodes[i].name || metaNodes[i].httpEquiv, metaNodes[i].content]);
 
     metaGroup.collapsed = false;
   }
 
   // get the date of last modification
--- a/browser/base/content/sync/quota.js
+++ b/browser/base/content/sync/quota.js
@@ -156,20 +156,19 @@ let gUsageTreeView = {
 
   /*
    * Handle click events on the tree.
    */
   onTreeClick: function onTreeClick(event) {
     if (event.button == 2)
       return;
 
-    let row = {}, col = {};
-    this.treeBox.getCellAt(event.clientX, event.clientY, row, col, {});
-    if (col.value && col.value.id == "enabled")
-      this.toggle(row.value);
+    let cell = this.treeBox.getCellAt(event.clientX, event.clientY);
+    if (cell.col && cell.col.id == "enabled")
+      this.toggle(cell.row);
   },
 
   /*
    * Toggle enabled state of an engine.
    */
   toggle: function toggle(row) {
     // Update the tree
     let collection = this._collections[row];
--- a/browser/components/feeds/FeedWriter.js
+++ b/browser/components/feeds/FeedWriter.js
@@ -853,17 +853,16 @@ FeedWriter.prototype = {
            * Application" item is being selected with the keyboard. We do this
            * by ignoring command events while the dropdown is closed (user
            * arrowing through the combobox), but handling them while the
            * combobox dropdown is open (user pressed enter when an item was
            * selected). If we don't show the filepicker here, it will be shown
            * when clicking "Subscribe Now".
            */
           var popupbox = this._handlersMenuList.firstChild.boxObject;
-          popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject);
           if (popupbox.popupState == "hiding") {
             this._chooseClientApp(function(aResult) {
               if (!aResult) {
                 // Select the (per-prefs) selected handler if no application
                 // was selected
                 this._setSelectedHandler(this._getFeedType());
               }
             }.bind(this));
--- a/browser/components/loop/test/functional/test_1_browser_call.py
+++ b/browser/components/loop/test/functional/test_1_browser_call.py
@@ -1,14 +1,14 @@
 from marionette_test import MarionetteTestCase
 from by import By
 import urlparse
-from marionette.errors import NoSuchElementException, StaleElementException
+from errors import NoSuchElementException, StaleElementException
 # noinspection PyUnresolvedReferences
-from marionette.wait import Wait
+from wait import Wait
 from time import sleep
 
 import os
 import sys
 sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
 
 from serversetup import LoopTestServers
 from config import *
--- a/browser/components/loop/test/xpcshell/head.js
+++ b/browser/components/loop/test/xpcshell/head.js
@@ -3,16 +3,17 @@
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Http.jsm");
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource:///modules/loop/MozLoopService.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
 const { MozLoopServiceInternal } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
 
 XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
                                   "resource:///modules/loop/MozLoopPushHandler.jsm");
 
 const kMockWebSocketChannelName = "Mock WebSocket Channel";
 const kWebSocketChannelContractID = "@mozilla.org/network/protocol;1?name=wss";
 
--- a/browser/components/places/content/sidebarUtils.js
+++ b/browser/components/places/content/sidebarUtils.js
@@ -5,66 +5,63 @@
 
 var SidebarUtils = {
   handleTreeClick: function SU_handleTreeClick(aTree, aEvent, aGutterSelect) {
     // right-clicks are not handled here
     if (aEvent.button == 2)
       return;
 
     var tbo = aTree.treeBoxObject;
-    var row = { }, col = { }, obj = { };
-    tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
+    var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
 
-    if (row.value == -1 || obj.value == "twisty")
+    if (cell.row == -1 || cell.childElt == "twisty")
       return;
 
     var mouseInGutter = false;
     if (aGutterSelect) {
-      var x = { }, y = { }, w = { }, h = { };
-      tbo.getCoordsForCellItem(row.value, col.value, "image",
-                               x, y, w, h);
+      var rect = tbo.getCoordsForCellItem(cell.row, cell.col, "image");
       // getCoordsForCellItem returns the x coordinate in logical coordinates
       // (i.e., starting from the left and right sides in LTR and RTL modes,
       // respectively.)  Therefore, we make sure to exclude the blank area
       // before the tree item icon (that is, to the left or right of it in
       // LTR and RTL modes, respectively) from the click target area.
       var isRTL = window.getComputedStyle(aTree, null).direction == "rtl";
       if (isRTL)
-        mouseInGutter = aEvent.clientX > x.value;
+        mouseInGutter = aEvent.clientX > rect.x;
       else
-        mouseInGutter = aEvent.clientX < x.value;
+        mouseInGutter = aEvent.clientX < rect.x;
     }
 
 #ifdef XP_MACOSX
     var modifKey = aEvent.metaKey || aEvent.shiftKey;
 #else
     var modifKey = aEvent.ctrlKey || aEvent.shiftKey;
 #endif
 
-    var isContainer = tbo.view.isContainer(row.value);
+    var isContainer = tbo.view.isContainer(cell.row);
     var openInTabs = isContainer &&
                      (aEvent.button == 1 ||
                       (aEvent.button == 0 && modifKey)) &&
-                     PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(row.value), true);
+                     PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(cell.row), true);
 
     if (aEvent.button == 0 && isContainer && !openInTabs) {
-      tbo.view.toggleOpenState(row.value);
+      tbo.view.toggleOpenState(cell.row);
       return;
     }
     else if (!mouseInGutter && openInTabs &&
             aEvent.originalTarget.localName == "treechildren") {
-      tbo.view.selection.select(row.value);
+      tbo.view.selection.select(cell.row);
       PlacesUIUtils.openContainerNodeInTabs(aTree.selectedNode, aEvent, aTree);
     }
     else if (!mouseInGutter && !isContainer &&
              aEvent.originalTarget.localName == "treechildren") {
       // Clear all other selection since we're loading a link now. We must
       // do this *before* attempting to load the link since openURL uses
       // selection as an indication of which link to load.
-      tbo.view.selection.select(row.value);
+      tbo.view.selection.select(cell.row);
       PlacesUIUtils.openNodeWithEvent(aTree.selectedNode, aEvent, aTree);
     }
   },
 
   handleTreeKeyPress: function SU_handleTreeKeyPress(aEvent) {
     // XXX Bug 627901: Post Fx4, this method should take a tree parameter.
     let tree = aEvent.target;
     let node = tree.selectedNode;
@@ -79,24 +76,23 @@ var SidebarUtils = {
    * hovered over.
    */
   handleTreeMouseMove: function SU_handleTreeMouseMove(aEvent) {
     if (aEvent.target.localName != "treechildren")
       return;
 
     var tree = aEvent.target.parentNode;
     var tbo = tree.treeBoxObject;
-    var row = { }, col = { }, obj = { };
-    tbo.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
+    var cell = tbo.getCellAt(aEvent.clientX, aEvent.clientY);
 
-    // row.value is -1 when the mouse is hovering an empty area within the tree.
+    // cell.row is -1 when the mouse is hovering an empty area within the tree.
     // To avoid showing a URL from a previously hovered node for a currently
     // hovered non-url node, we must clear the moused-over URL in these cases.
-    if (row.value != -1) {
-      var node = tree.view.nodeForTreeIndex(row.value);
+    if (cell.row != -1) {
+      var node = tree.view.nodeForTreeIndex(cell.row);
       if (PlacesUtils.nodeIsURI(node))
         this.setMouseoverURL(node.uri);
       else
         this.setMouseoverURL("");
     }
     else
       this.setMouseoverURL("");
   },
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -742,52 +742,50 @@
         this._controller.setDataTransfer(event);
         event.stopPropagation();
       ]]></handler>
 
       <handler event="dragover"><![CDATA[
         if (event.target.localName != "treechildren")
           return;
 
-        let row = { }, col = { }, child = { };
-        this.treeBoxObject.getCellAt(event.clientX, event.clientY,
-                                     row, col, child);
-        let node = row.value != -1 ?
-                   this.view.nodeForTreeIndex(row.value) :
+        let cell = this.treeBoxObject.getCellAt(event.clientX, event.clientY);
+        let node = cell.row != -1 ?
+                   this.view.nodeForTreeIndex(cell.row) :
                    this.result.root;
         // cache the dropTarget for the view
         PlacesControllerDragHelper.currentDropTarget = node;
 
         // We have to calculate the orientation since view.canDrop will use
         // it and we want to be consistent with the dropfeedback.
         let tbo = this.treeBoxObject;
         let rowHeight = tbo.rowHeight;
         let eventY = event.clientY - tbo.treeBody.boxObject.y -
-                     rowHeight * (row.value - tbo.getFirstVisibleRow());
+                     rowHeight * (cell.row - tbo.getFirstVisibleRow());
 
         let orientation = Ci.nsITreeView.DROP_BEFORE;
 
-        if (row.value == -1) {
+        if (cell.row == -1) {
           // If the row is not valid we try to insert inside the resultNode.
           orientation = Ci.nsITreeView.DROP_ON;
         }
         else if (PlacesUtils.nodeIsContainer(node) &&
                  eventY > rowHeight * 0.75) {
           // If we are below the 75% of a container the treeview we try
           // to drop after the node.
           orientation = Ci.nsITreeView.DROP_AFTER;
         }
         else if (PlacesUtils.nodeIsContainer(node) &&
                  eventY > rowHeight * 0.25) {
           // If we are below the 25% of a container the treeview we try
           // to drop inside the node.
           orientation = Ci.nsITreeView.DROP_ON;
         }
 
-        if (!this.view.canDrop(row.value, orientation, event.dataTransfer))
+        if (!this.view.canDrop(cell.row, orientation, event.dataTransfer))
           return;
 
         event.preventDefault();
         event.stopPropagation();
       ]]></handler>
 
       <handler event="dragend"><![CDATA[
         PlacesControllerDragHelper.currentDropTarget = null;
--- a/browser/components/places/tests/browser/browser_forgetthissite_single.js
+++ b/browser/components/places/tests/browser/browser_forgetthissite_single.js
@@ -57,17 +57,14 @@ function test() {
               organizer.removeEventListener("unload", arguments.callee, false);
               // Proceed
               funcNext();
             }, false);
             // Close Library window.
             organizer.close();
           }, true);
           // Get cell coordinates
-          var x = {}, y = {}, width = {}, height = {};
-          tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "text",
-                                                  x, y, width, height);
+          var rect = tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "text");
           // Initiate a context menu for the selected cell
-          EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, {type: "contextmenu"}, organizer);
+          EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {type: "contextmenu"}, organizer);
     });
   }
 }
-
--- a/browser/components/places/tests/browser/browser_library_infoBox.js
+++ b/browser/components/places/tests/browser/browser_library_infoBox.js
@@ -47,17 +47,17 @@ gTests.push({
       isnot(childNode, null, "History node first child is not null.");
       PO._places.selectNode(childNode);
       checkInfoBoxSelected(PO);
       ok(infoBoxExpanderWrapper.hidden,
          "Expander button is hidden for history child node.");
       checkAddInfoFieldsCollapsed(PO);
 
       // open history item
-      var view = ContentTree.view.treeBoxObject.view;
+      var view = ContentTree.view.view;
       ok(view.rowCount > 0, "History item exists.");
       view.selection.select(0);
       ok(infoBoxExpanderWrapper.hidden,
          "Expander button is hidden for history item.");
       checkAddInfoFieldsCollapsed(PO);
 
       historyNode.containerOpen = false;
 
@@ -84,17 +84,17 @@ gTests.push({
          "Correctly selected recently bookmarked node.");
       PO._places.selectNode(childNode);
       checkInfoBoxSelected(PO);
       ok(!infoBoxExpanderWrapper.hidden,
          "Expander button is not hidden for recently bookmarked node.");
       checkAddInfoFieldsNotCollapsed(PO);
 
       // open first bookmark
-      var view = ContentTree.view.treeBoxObject.view;
+      var view = ContentTree.view.view;
       ok(view.rowCount > 0, "Bookmark item exists.");
       view.selection.select(0);
       checkInfoBoxSelected(PO);
       ok(!infoBoxExpanderWrapper.hidden,
          "Expander button is not hidden for bookmark item.");
       checkAddInfoFieldsNotCollapsed(PO);
       checkAddInfoFields(PO, "bookmark item");
 
--- a/browser/components/places/tests/browser/browser_library_middleclick.js
+++ b/browser/components/places/tests/browser/browser_library_middleclick.js
@@ -267,15 +267,13 @@ function runNextTest() {
 
 function mouseEventOnCell(aTree, aRowIndex, aColumnIndex, aEventDetails) {
   var selection = aTree.view.selection;
   selection.select(aRowIndex);
   aTree.treeBoxObject.ensureRowIsVisible(aRowIndex);
   var column = aTree.columns[aColumnIndex];
 
   // get cell coordinates
-  var x = {}, y = {}, width = {}, height = {};
-  aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text",
-                                           x, y, width, height);
+  var rect = aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text");
 
-  EventUtils.synthesizeMouse(aTree.body, x.value, y.value,
+  EventUtils.synthesizeMouse(aTree.body, rect.x, rect.y,
                              aEventDetails, gLibrary);
 }
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -191,17 +191,15 @@ function synthesizeClickOnSelectedTreeCe
   if (tbo.view.selection.count != 1)
      throw new Error("The test node should be successfully selected");
   // Get selection rowID.
   let min = {}, max = {};
   tbo.view.selection.getRangeAt(0, min, max);
   let rowID = min.value;
   tbo.ensureRowIsVisible(rowID);
   // Calculate the click coordinates.
-  let x = {}, y = {}, width = {}, height = {};
-  tbo.getCoordsForCellItem(rowID, aTree.columns[0], "text",
-                           x, y, width, height);
-  x = x.value + width.value / 2;
-  y = y.value + height.value / 2;
+  var rect = tbo.getCoordsForCellItem(rowID, aTree.columns[0], "text");
+  var x = rect.x + rect.width / 2;
+  var y = rect.y + rect.height / 2;
   // Simulate the click.
   EventUtils.synthesizeMouse(aTree.body, x, y, aOptions || {},
                              aTree.ownerDocument.defaultView);
 }
--- a/browser/components/preferences/cookies.js
+++ b/browser/components/preferences/cookies.js
@@ -33,17 +33,17 @@ var gCookiesWindow = {
     var os = Components.classes["@mozilla.org/observer-service;1"]
                        .getService(Components.interfaces.nsIObserverService);
     os.removeObserver(this, "cookie-changed");
     os.removeObserver(this, "perm-changed");
   },
 
   _populateList: function (aInitialLoad) {
     this._loadCookies();
-    this._tree.treeBoxObject.view = this._view;
+    this._tree.view = this._view;
     if (aInitialLoad)
       this.sort("rawHost");
     if (this._view.rowCount > 0)
       this._tree.view.selection.select(0);
 
     if (aInitialLoad) {
       if ("arguments" in window &&
           window.arguments[0] &&
@@ -785,17 +785,17 @@ var gCookiesWindow = {
     // Clear the Tree Display
     this._view._filtered = false;
     this._view._rowCount = 0;
     this._tree.treeBoxObject.rowCountChanged(0, -this._view._filterSet.length);
     this._view._filterSet = [];
 
     // Just reload the list to make sure deletions are respected
     this._loadCookies();
-    this._tree.treeBoxObject.view = this._view;
+    this._tree.view = this._view;
 
     // Restore sort order
     var sortby = this._lastSortProperty;
     if (sortby == "") {
       this._lastSortAscending = false;
       this.sort("rawHost");
     }
     else {
--- a/browser/components/preferences/permissions.js
+++ b/browser/components/preferences/permissions.js
@@ -327,17 +327,17 @@ var gPermissionManager = {
     while (enumerator.hasMoreElements()) {
       var nextPermission = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
       this._addPermissionToList(nextPermission);
     }
    
     this._view._rowCount = this._permissions.length;
 
     // sort and display the table
-    this._tree.treeBoxObject.view = this._view;
+    this._tree.view = this._view;
     this.onPermissionSort("rawHost", false);
 
     // disable "remove all" button if there are none
     document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0;
   },
   
   _addPermissionToList: function (aPermission)
   {
@@ -365,9 +365,8 @@ function setHost(aHost)
 {
   gPermissionManager.setHost(aHost);
 }
 
 function initWithParams(aParams)
 {
   gPermissionManager.init(aParams);
 }
-
--- a/browser/components/preferences/tests/browser_bug705422.js
+++ b/browser/components/preferences/tests/browser_bug705422.js
@@ -77,34 +77,33 @@ function runTest(win, searchTerm, cookie
 
     // "delete all cookies" should be enabled
     isDisabled(win, false);
 
 
     // select first cookie and delete
     var tree = win.document.getElementById("cookiesList");
     var deleteButton = win.document.getElementById("removeCookie");
-    var x = {}, y = {}, width = {}, height = {};
-    tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "cell", x, y, width, height);
-    EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, {}, win);
+    var rect = tree.treeBoxObject.getCoordsForCellItem(0, tree.columns[0], "cell");
+    EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {}, win);
     EventUtils.synthesizeMouseAtCenter(deleteButton, {}, win);
 
     // count cookies should be matches-1
     is(win.gCookiesWindow._view.rowCount, matches-1, "Deleted selected cookie");
 
     // select two adjacent cells and delete
-    EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, {}, win);
+    EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, {}, win);
     deleteButton = win.document.getElementById("removeCookies"); 
     var eventObj = {};
     if (navigator.platform.indexOf("Mac") >= 0)
         eventObj.metaKey = true;
     else
         eventObj.ctrlKey = true;
-    tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell", x, y, width, height);
-    EventUtils.synthesizeMouse(tree.body, x.value + width.value / 2, y.value + height.value / 2, eventObj, win);
+    rect = tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[0], "cell");
+    EventUtils.synthesizeMouse(tree.body, rect.x + rect.width / 2, rect.y + rect.height / 2, eventObj, win);
     EventUtils.synthesizeMouseAtCenter(deleteButton, {}, win);
 
     // count cookies should be matches-3
     is(win.gCookiesWindow._view.rowCount, matches-3, "Deleted selected two adjacent cookies");
 
     // "delete all cookies" should be enabled
     isDisabled(win, false);
 
--- a/browser/components/preferences/translation.js
+++ b/browser/components/preferences/translation.js
@@ -15,17 +15,17 @@ XPCOMUtils.defineLazyGetter(this, "gLang
 
 const kPermissionType = "translate";
 const kLanguagesPref = "browser.translation.neverForLanguages";
 
 function Tree(aId, aData)
 {
   this._data = aData;
   this._tree = document.getElementById(aId);
-  this._tree.treeBoxObject.view = this;
+  this._tree.view = this;
 }
 
 Tree.prototype = {
   get boxObject() this._tree.treeBoxObject,
   get isEmpty() !this._data.length,
   get hasSelection() this.selection.count > 0,
   getSelectedItems: function() {
     let result = [];
--- a/browser/components/search/test/browser_405664.js
+++ b/browser/components/search/test/browser_405664.js
@@ -1,16 +1,16 @@
 function test() {
   var searchBar = BrowserSearch.searchBar;
   ok(searchBar, "got search bar");
   
   searchBar.focus();
 
   var pbo = searchBar._popup.popupBoxObject;
-  ok(pbo, "popup is nsIPopupBoxObject");
+  ok(pbo, "popup is PopupBoxObject");
 
   EventUtils.synthesizeKey("VK_UP", { altKey: true });
   is(pbo.popupState, "showing", "popup is opening after Alt+Up");
 
   EventUtils.synthesizeKey("VK_ESCAPE", {});
   is(pbo.popupState, "closed", "popup is closed after ESC");
 
   EventUtils.synthesizeKey("VK_DOWN", { altKey: true });
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -139,34 +139,33 @@ function startNewSession() {
     getBrowserWindow().BrowserHome();
 }
 
 function onListClick(aEvent) {
   // don't react to right-clicks
   if (aEvent.button == 2)
     return;
 
-  var row = {}, col = {};
-  treeView.treeBox.getCellAt(aEvent.clientX, aEvent.clientY, row, col, {});
-  if (col.value) {
+  var cell = treeView.treeBox.getCellAt(aEvent.clientX, aEvent.clientY);
+  if (cell.col) {
     // Restore this specific tab in the same window for middle/double/accel clicking
     // on a tab's title.
 #ifdef XP_MACOSX
     let accelKey = aEvent.metaKey;
 #else
     let accelKey = aEvent.ctrlKey;
 #endif
     if ((aEvent.button == 1 || aEvent.button == 0 && aEvent.detail == 2 || accelKey) &&
-        col.value.id == "title" &&
-        !treeView.isContainer(row.value)) {
-      restoreSingleTab(row.value, aEvent.shiftKey);
+        cell.col.id == "title" &&
+        !treeView.isContainer(cell.row)) {
+      restoreSingleTab(cell.row, aEvent.shiftKey);
       aEvent.stopPropagation();
     }
-    else if (col.value.id == "restore")
-      toggleRowChecked(row.value);
+    else if (cell.col.id == "restore")
+      toggleRowChecked(cell.row);
   }
 }
 
 function onListKeyDown(aEvent) {
   switch (aEvent.keyCode)
   {
   case KeyEvent.DOM_VK_SPACE:
     toggleRowChecked(document.getElementById("tabList").currentIndex);
--- a/browser/components/sessionstore/test/browser_590563.js
+++ b/browser/components/sessionstore/test/browser_590563.js
@@ -33,25 +33,23 @@ function test() {
   });
 }
 
 function middleClickTest(win) {
   let browser = win.gBrowser.selectedBrowser;
   let tree = browser.contentDocument.getElementById("tabList");
   is(tree.view.rowCount, 3, "There should be three items");
 
-  let x = {}, y = {}, width = {}, height = {};
-
   // click on the first tab item
-  tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[1], "text", x, y, width, height);
-  EventUtils.synthesizeMouse(tree.body, x.value, y.value, { button: 1 },
+  var rect = tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[1], "text");
+  EventUtils.synthesizeMouse(tree.body, rect.x, rect.y, { button: 1 },
                              browser.contentWindow);
   // click on the second tab item
-  tree.treeBoxObject.getCoordsForCellItem(2, tree.columns[1], "text", x, y, width, height);
-  EventUtils.synthesizeMouse(tree.body, x.value, y.value, { button: 1 },
+  rect = tree.treeBoxObject.getCoordsForCellItem(2, tree.columns[1], "text");
+  EventUtils.synthesizeMouse(tree.body, rect.x, rect.y, { button: 1 },
                              browser.contentWindow);
 
   is(win.gBrowser.tabs.length, 3,
      "The total number of tabs should be 3 after restoring 2 tabs by middle click.");
   is(win.gBrowser.visibleTabs.length, 3,
      "The total number of visible tabs should be 3 after restoring 2 tabs by middle click");
 }
 
--- a/browser/devtools/shared/widgets/FastListWidget.js
+++ b/browser/devtools/shared/widgets/FastListWidget.js
@@ -190,17 +190,17 @@ FastListWidget.prototype = {
    *        The element to make visible.
    */
   ensureElementIsVisible: function(element) {
     if (!element) {
       return;
     }
 
     // Ensure the element is visible but not scrolled horizontally.
-    let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+    let boxObject = this._list.boxObject;
     boxObject.ensureElementIsVisible(element);
     boxObject.scrollBy(-this._list.clientWidth, 0);
   },
 
   /**
    * Sets the text displayed in this container when empty.
    * @param string aValue
    */
--- a/browser/devtools/shared/widgets/SideMenuWidget.jsm
+++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm
@@ -209,17 +209,17 @@ SideMenuWidget.prototype = {
    *        The element to make visible.
    */
   ensureElementIsVisible: function(aElement) {
     if (!aElement) {
       return;
     }
 
     // Ensure the element is visible but not scrolled horizontally.
-    let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+    let boxObject = this._list.boxObject;
     boxObject.ensureElementIsVisible(aElement);
     boxObject.scrollBy(-this._list.clientWidth, 0);
   },
 
   /**
    * Shows all the groups, even the ones with no visible children.
    */
   showEmptyGroups: function() {
--- a/browser/devtools/shared/widgets/SimpleListWidget.jsm
+++ b/browser/devtools/shared/widgets/SimpleListWidget.jsm
@@ -166,17 +166,17 @@ SimpleListWidget.prototype = {
    *        The element to make visible.
    */
   ensureElementIsVisible: function(aElement) {
     if (!aElement) {
       return;
     }
 
     // Ensure the element is visible but not scrolled horizontally.
-    let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+    let boxObject = this._list.boxObject;
     boxObject.ensureElementIsVisible(aElement);
     boxObject.scrollBy(-this._list.clientWidth, 0);
   },
 
   /**
    * Sets the text displayed permanently in this container as a header.
    * @param string aValue
    */
--- a/browser/devtools/shared/widgets/VariablesView.jsm
+++ b/browser/devtools/shared/widgets/VariablesView.jsm
@@ -982,17 +982,17 @@ VariablesView.prototype = {
       this._parent.removeAttribute("actions-first");
     }
   },
 
   /**
    * Gets the parent node holding this view.
    * @return nsIDOMNode
    */
-  get boxObject() this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject),
+  get boxObject() this._list.boxObject,
 
   /**
    * Gets the parent node holding this view.
    * @return nsIDOMNode
    */
   get parentNode() this._parent,
 
   /**
--- a/browser/metro/base/content/bindings/bindings.xml
+++ b/browser/metro/base/content/bindings/bindings.xml
@@ -20,24 +20,21 @@
     <handlers>
       <handler event="scroll">
         <![CDATA[
           // if there no more items to insert, just return early
           if (this._items.length == 0)
             return;
 
           if (this._contentScrollHeight == -1) {
-            let scrollheight = {};
-            this.scrollBoxObject.getScrolledSize({}, scrollheight);
-            this._contentScrollHeight = scrollheight.value;
+            this._contentScrollHeight = this.scrollBoxObject.scrolledHeight;
           }
 
-          let y = {};
-          this.scrollBoxObject.getPosition({}, y);
-          let scrollRatio = (y.value + this._childrenHeight) / this._contentScrollHeight;
+          let y = this.scrollBoxObject.positionY;
+          let scrollRatio = (y + this._childrenHeight) / this._contentScrollHeight;
 
           // If we're scrolled 80% to the bottom of the list, append the next
           // set of items
           if (scrollRatio > 0.8)
             this._insertItems();
         ]]>
       </handler>
     </handlers>
--- a/browser/metro/base/content/input.js
+++ b/browser/metro/base/content/input.js
@@ -470,27 +470,27 @@ var ScrollUtils = {
     // if element is content or the startui page, get the browser scroll interface
     if (elem.ownerDocument == Browser.selectedBrowser.contentDocument) {
       elem = Browser.selectedBrowser;
     }
     for (; elem; elem = elem.parentNode) {
       try {
         if (elem.anonScrollBox) {
           scrollbox = elem.anonScrollBox;
-          qinterface = scrollbox.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+          qinterface = scrollbox.boxObject;
         } else if (elem.scrollBoxObject) {
           scrollbox = elem;
           qinterface = elem.scrollBoxObject;
           break;
         } else if (elem.customDragger) {
           scrollbox = elem;
           break;
         } else if (elem.boxObject) {
           let qi = (elem._cachedSBO) ? elem._cachedSBO
-                                     : elem.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+                                     : elem.boxObject;
           if (qi) {
             scrollbox = elem;
             scrollbox._cachedSBO = qinterface = qi;
             break;
           }
         }
       } catch (e) { /* we aren't here to deal with your exceptions, we'll just keep
                        traversing until we find something more well-behaved, as we
@@ -507,50 +507,43 @@ var ScrollUtils = {
 
   /**
    * The default dragger object used by TouchModule when dragging a scrollable
    * element that provides no customDragger.  Simply performs the expected
    * regular scrollBy calls on the scroller.
    */
   _defaultDragger: {
     isDraggable: function isDraggable(target, scroller) {
-      let sX = {}, sY = {},
-          pX = {}, pY = {};
-      scroller.getPosition(pX, pY);
-      scroller.getScrolledSize(sX, sY);
       let rect = target.getBoundingClientRect();
-      return { x: (sX.value > rect.width  || pX.value != 0),
-               y: (sY.value > rect.height || pY.value != 0) };
+      return { x: (scroller.scrolledWidth > rect.width   || scroller.positionX != 0),
+               y: (scroller.scrolledHeight > rect.height || scroller.positionY != 0) };
     },
 
     dragStart: function dragStart(cx, cy, target, scroller) {
       scroller.element.addEventListener("PanBegin", this._showScrollbars, false);
     },
 
     dragStop: function dragStop(dx, dy, scroller) {
       scroller.element.removeEventListener("PanBegin", this._showScrollbars, false);
       return this.dragMove(dx, dy, scroller);
     },
 
     dragMove: function dragMove(dx, dy, scroller) {
-      if (scroller.getPosition) {
         try {
-          let oldX = {}, oldY = {};
-          scroller.getPosition(oldX, oldY);
+        let oldX = scroller.positionX,
+            oldY = scroller.positionY;
 
           scroller.scrollBy(dx, dy);
 
-          let newX = {}, newY = {};
-          scroller.getPosition(newX, newY);
+        let newX = scroller.positionX,
+            newY = scroller.positionY;
 
-          return (newX.value != oldX.value) || (newY.value != oldY.value);
+        return (newX != oldX) || (newY != oldY);
 
         } catch (e) { /* we have no time for whiny scrollers! */ }
-      }
-
       return false;
     },
 
     _showScrollbars: function _showScrollbars(aEvent) {
       let scrollbox = aEvent.target;
       scrollbox.setAttribute("panning", "true");
 
       let hideScrollbars = function() {
--- a/browser/modules/UITour.jsm
+++ b/browser/modules/UITour.jsm
@@ -1064,17 +1064,17 @@ this.UITour = {
     function openMenuButton(aMenuBtn) {
       if (!aMenuBtn || !aMenuBtn.boxObject || aMenuBtn.open) {
         if (aOpenCallback)
           aOpenCallback();
         return;
       }
       if (aOpenCallback)
         aMenuBtn.addEventListener("popupshown", onPopupShown);
-      aMenuBtn.boxObject.QueryInterface(Ci.nsIMenuBoxObject).openMenu(true);
+      aMenuBtn.boxObject.openMenu(true);
     }
     function onPopupShown(event) {
       this.removeEventListener("popupshown", onPopupShown);
       aOpenCallback(event);
     }
 
     if (aMenuName == "appMenu") {
       aWindow.PanelUI.panel.setAttribute("noautohide", "true");
@@ -1096,17 +1096,17 @@ this.UITour = {
         openMenuButton(target.node);
       }).catch(Cu.reportError);
     }
   },
 
   hideMenu: function(aWindow, aMenuName) {
     function closeMenuButton(aMenuBtn) {
       if (aMenuBtn && aMenuBtn.boxObject)
-        aMenuBtn.boxObject.QueryInterface(Ci.nsIMenuBoxObject).openMenu(false);
+        aMenuBtn.boxObject.openMenu(false);
     }
 
     if (aMenuName == "appMenu") {
       aWindow.PanelUI.panel.removeAttribute("noautohide");
       aWindow.PanelUI.hide();
       this.recreatePopup(aWindow.PanelUI.panel);
     } else if (aMenuName == "bookmarks") {
       let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
deleted file mode 100644
--- a/build/autoconf/ccache.m4
+++ /dev/null
@@ -1,36 +0,0 @@
-dnl This Source Code Form is subject to the terms of the Mozilla Public
-dnl License, v. 2.0. If a copy of the MPL was not distributed with this
-dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-dnl ======================================================
-dnl = Enable compiling with ccache
-dnl ======================================================
-AC_DEFUN([MOZ_CHECK_CCACHE],
-[
-MOZ_ARG_WITH_STRING(ccache,
-[  --with-ccache[=path/to/ccache]
-                          Enable compiling with ccache],
-    CCACHE=$withval, CCACHE="no")
-
-if test "$CCACHE" != "no"; then
-    if test -z "$CCACHE" -o "$CCACHE" = "yes"; then
-        CCACHE=
-    else
-        if test ! -e "$CCACHE"; then
-            AC_MSG_ERROR([$CCACHE not found])
-        fi
-    fi
-    MOZ_PATH_PROGS(CCACHE, $CCACHE ccache)
-    if test -z "$CCACHE" -o "$CCACHE" = ":"; then
-        AC_MSG_ERROR([ccache not found])
-    elif test -x "$CCACHE"; then
-        CC="$CCACHE $CC"
-        CXX="$CCACHE $CXX"
-        MOZ_USING_CCACHE=1
-    else
-        AC_MSG_ERROR([$CCACHE is not executable])
-    fi
-fi
-
-AC_SUBST(MOZ_USING_CCACHE)
-])
--- a/build/autoconf/nspr-build.m4
+++ b/build/autoconf/nspr-build.m4
@@ -192,16 +192,21 @@ AC_SUBST(NSPR_PKGCONF_CHECK)
 fi # _IS_OUTER_CONFIGURE
 
 ])
 
 AC_DEFUN([MOZ_SUBCONFIGURE_NSPR], [
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     ac_configure_args="$_SUBDIR_CONFIG_ARGS --with-dist-prefix=$MOZ_BUILD_ROOT/dist --with-mozilla"
+    if test -n "$MOZ_USING_CCACHE"; then
+        # Avoid double prepending ccache by omitting --with-ccache in building NSPR.
+        ac_configure_args="`echo $ac_configure_args | sed -e 's/--with-ccache[[^ ]]*//'`"
+    fi
+
     if test -z "$MOZ_DEBUG"; then
         ac_configure_args="$ac_configure_args --disable-debug"
     else
         ac_configure_args="$ac_configure_args --enable-debug"
         if test -n "$MOZ_NO_DEBUG_RTL"; then
             ac_configure_args="$ac_configure_args --disable-debug-rtl"
         fi
     fi
--- a/build/autoconf/wrapper.m4
+++ b/build/autoconf/wrapper.m4
@@ -7,16 +7,46 @@ dnl = Enable compiling with various comp
 dnl =======================================================================
 AC_DEFUN([MOZ_CHECK_COMPILER_WRAPPER],
 [
 MOZ_ARG_WITH_STRING(compiler_wrapper,
 [  --with-compiler-wrapper[=path/to/wrapper]
     Enable compiling with wrappers such as distcc and ccache],
     COMPILER_WRAPPER=$withval, COMPILER_WRAPPER="no")
 
+MOZ_ARG_WITH_STRING(ccache,
+[  --with-ccache[=path/to/ccache]
+                          Enable compiling with ccache],
+    CCACHE=$withval, CCACHE="no")
+
+if test "$CCACHE" != "no"; then
+    if test -z "$CCACHE" -o "$CCACHE" = "yes"; then
+        CCACHE=
+    else
+        if test ! -e "$CCACHE"; then
+            AC_MSG_ERROR([$CCACHE not found])
+        fi
+    fi
+    MOZ_PATH_PROGS(CCACHE, $CCACHE ccache)
+    if test -z "$CCACHE" -o "$CCACHE" = ":"; then
+        AC_MSG_ERROR([ccache not found])
+    elif test -x "$CCACHE"; then
+        if test "$COMPILER_WRAPPER" != "no"; then
+            COMPILER_WRAPPER="$CCACHE $COMPILER_WRAPPER"
+        else
+            COMPILER_WRAPPER="$CCACHE"
+        fi
+        MOZ_USING_CCACHE=1
+    else
+        AC_MSG_ERROR([$CCACHE is not executable])
+    fi
+fi
+
+AC_SUBST(MOZ_USING_CCACHE)
+
 if test "$COMPILER_WRAPPER" != "no"; then
     case "$target" in
     *-mingw*)
         dnl When giving a windows path with backslashes, js/src/configure
         dnl fails because of double wrapping because the test further below
         dnl doesn't work with backslashes. While fixing that test to work
         dnl might seem better, a lot of the make build backend actually
         dnl doesn't like backslashes, so normalize windows paths to use
--- a/client.mk
+++ b/client.mk
@@ -86,16 +86,19 @@ ifneq (,$(findstring mingw,$(CONFIG_GUES
 
 # check for CRLF line endings
 ifneq (0,$(shell $(PERL) -e 'binmode(STDIN); while (<STDIN>) { if (/\r/) { print "1"; exit } } print "0"' < $(TOPSRCDIR)/client.mk))
 $(error This source tree appears to have Windows-style line endings. To \
 convert it to Unix-style line endings, check \
 "https://developer.mozilla.org/en-US/docs/Developer_Guide/Mozilla_build_FAQ\#Win32-specific_questions" \
 for a workaround of this issue.)
 endif
+
+# Set this for baseconfig.mk
+HOST_OS_ARCH=WINNT
 endif
 
 ####################################
 # Load mozconfig Options
 
 # See build pages, http://www.mozilla.org/build/ for how to set up mozconfig.
 
 define CR
@@ -162,16 +165,19 @@ OBJDIR_TARGETS = install export libs cle
 
 #######################################################################
 # Rules
 
 # The default rule is build
 build::
 	$(MAKE) -f $(TOPSRCDIR)/client.mk $(if $(MOZ_PGO),profiledbuild,realbuild) CREATE_MOZCONFIG_JSON=
 
+# Include baseconfig.mk for its $(MAKE) validation.
+include $(TOPSRCDIR)/config/baseconfig.mk
+
 # Define mkdir
 include $(TOPSRCDIR)/config/makefiles/makeutils.mk
 include $(TOPSRCDIR)/config/makefiles/autotargets.mk
 
 # Create a makefile containing the mk_add_options values from mozconfig,
 # but only do so when OBJDIR is defined (see further above).
 ifdef MOZ_BUILD_PROJECTS
 ifdef MOZ_CURRENT_PROJECT
--- a/configure.in
+++ b/configure.in
@@ -7322,18 +7322,16 @@ dnl ====================================
 MOZ_ARG_ENABLE_BOOL(gczeal,
 [  --enable-gczeal         Enable zealous JavaScript GCing],
     JS_GC_ZEAL=1,
     JS_GC_ZEAL= )
 if test -n "$JS_GC_ZEAL" -o -n "$MOZ_DEBUG"; then
     AC_DEFINE(JS_GC_ZEAL)
 fi
 
-MOZ_CHECK_CCACHE
-
 dnl ========================================================
 dnl = Enable static checking using gcc-dehydra
 dnl ========================================================
 
 MOZ_ARG_WITH_STRING(static-checking,
 [  --with-static-checking=path/to/gcc_dehydra.so
                           Enable static checking of code using GCC-dehydra],
     DEHYDRA_PATH=$withval,
@@ -9187,21 +9185,16 @@ if test -n "$_subconfigure_subdir"; then
   srcdir="$_save_srcdir"
 fi
 
 # No need to run subconfigures when building with LIBXUL_SDK_DIR
 if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
 
 export WRAP_LDFLAGS
 
-if test -n "$MOZ_USING_CCACHE"; then
-    # Avoid double prepending ccache by omitting --with-ccache in building NSPR.
-    _SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--with-ccache[[^ ]]*//'`"
-fi
-
 MOZ_SUBCONFIGURE_NSPR()
 
 dnl ========================================================
 dnl = Setup a nice relatively clean build environment for
 dnl = sub-configures.
 dnl ========================================================
 CC="$_SUBDIR_CC"
 CXX="$_SUBDIR_CXX"
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -128,18 +128,18 @@ class AnimationPlayer;
 class Link;
 class UndoManager;
 class DOMRect;
 class DOMRectList;
 class DestinationInsertionPointList;
 
 // IID for the dom::Element interface
 #define NS_ELEMENT_IID \
-{ 0xb0135f9d, 0xa476, 0x4711, \
-  { 0x8b, 0xb9, 0xca, 0xe5, 0x2a, 0x05, 0xf9, 0xbe } }
+{ 0xaa79cb98, 0xc785, 0x44c5, \
+  { 0x80, 0x80, 0x2e, 0x5f, 0x0c, 0xa5, 0xbd, 0x63 } }
 
 class Element : public FragmentOrElement
 {
 public:
 #ifdef MOZILLA_INTERNAL_API
   explicit Element(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) :
     FragmentOrElement(aNodeInfo),
     mState(NS_EVENT_STATE_MOZ_READONLY)
@@ -669,16 +669,20 @@ public:
   }
   void SetPointerCapture(int32_t aPointerId, ErrorResult& aError)
   {
     bool activeState = false;
     if (!nsIPresShell::GetPointerInfo(aPointerId, activeState)) {
       aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
       return;
     }
+    if (!IsInDoc()) {
+      aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+      return;
+    }
     if (!activeState) {
       return;
     }
     nsIPresShell::SetPointerCapturingContent(aPointerId, this);
   }
   void ReleasePointerCapture(int32_t aPointerId, ErrorResult& aError)
   {
     bool activeState = false;
--- a/content/base/public/File.h
+++ b/content/base/public/File.h
@@ -86,21 +86,27 @@ public:
   static already_AddRefed<File>
   Create(nsISupports* aParent, const nsAString& aContentType,
          uint64_t aLength);
 
   static already_AddRefed<File>
   Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
          uint64_t aLength);
 
+  // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
+  // freed by moz_free so it must be allocated by moz_malloc or something
+  // compatible with it.
   static already_AddRefed<File>
   CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aName, const nsAString& aContentType,
                    uint64_t aLastModifiedDate);
 
+  // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
+  // freed by moz_free so it must be allocated by moz_malloc or something
+  // compatible with it.
   static already_AddRefed<File>
   CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aContentType);
 
   static already_AddRefed<File>
   CreateTemporaryFileBlob(nsISupports* aParent, PRFileDesc* aFD,
                           uint64_t aStartPos, uint64_t aLength,
                           const nsAString& aContentType);
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -33,17 +33,16 @@ class nsIDocShell;
 class nsDocShell;
 class nsDOMNavigationTiming;
 class nsFrameLoader;
 class nsHTMLCSSStyleSheet;
 class nsHTMLDocument;
 class nsHTMLStyleSheet;
 class nsIAtom;
 class nsIBFCacheEntry;
-class nsIBoxObject;
 class nsIChannel;
 class nsIContent;
 class nsIContentSink;
 class nsIDocShell;
 class nsIDocumentEncoder;
 class nsIDocumentObserver;
 class nsIDOMDocument;
 class nsIDOMDocumentFragment;
@@ -90,16 +89,17 @@ class SVGAttrAnimationRuleProcessor;
 namespace css {
 class Loader;
 class ImageLoader;
 } // namespace css
 
 namespace dom {
 class AnimationTimeline;
 class Attr;
+class BoxObject;
 class CDATASection;
 class Comment;
 struct CustomElementDefinition;
 class DocumentFragment;
 class DocumentType;
 class DOMImplementation;
 class DOMStringList;
 class Element;
@@ -1495,17 +1495,17 @@ public:
    * @param aElement canonical nsIContent pointer of the box object's element
    */
   virtual void ClearBoxObjectFor(nsIContent *aContent) = 0;
 
   /**
    * Get the box object for an element. This is not exposed through a
    * scriptable interface except for XUL documents.
    */
-  virtual already_AddRefed<nsIBoxObject>
+  virtual already_AddRefed<mozilla::dom::BoxObject>
     GetBoxObjectFor(mozilla::dom::Element* aElement,
                     mozilla::ErrorResult& aRv) = 0;
 
   /**
    * Get the compatibility mode for this document
    */
   nsCompatibility GetCompatibilityMode() const {
     return mCompatMode;
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -243,18 +243,18 @@ private:
 
 // Categories of node properties
 // 0 is global.
 #define DOM_USER_DATA         1
 #define SMIL_MAPPED_ATTR_ANIMVAL 2
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0x3a60353e, 0x04e5, 0x49ca, \
-  { 0x84, 0x1c, 0x59, 0xc6, 0xde, 0xe6, 0x36, 0xcc } }
+{ 0x8deda3f4, 0x0f45, 0x497a, \
+  { 0x89, 0x7c, 0xe6, 0x09, 0x12, 0x8a, 0xad, 0xd8 } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public mozilla::dom::EventTarget
 {
--- a/content/base/src/ImportManager.cpp
+++ b/content/base/src/ImportManager.cpp
@@ -479,17 +479,17 @@ ImportLoader::Open()
     return;
   }
 
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   rv = secMan->CheckLoadURIWithPrincipal(principal, mURI,
                                          nsIScriptSecurityManager::STANDARD);
   NS_ENSURE_SUCCESS_VOID(rv);
 
-  nsCOMPtr<nsILoadGroup> loadGroup = mImportParent->GetDocumentLoadGroup();
+  nsCOMPtr<nsILoadGroup> loadGroup = master->GetDocumentLoadGroup();
   nsCOMPtr<nsIChannelPolicy> channelPolicy;
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = principal->GetCsp(getter_AddRefs(csp));
   NS_ENSURE_SUCCESS_VOID(rv);
 
   if (csp) {
     channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
     channelPolicy->SetContentSecurityPolicy(csp);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -215,16 +215,17 @@
 #include "nsIDocumentActivity.h"
 #include "nsIStructuredCloneContainer.h"
 #include "nsIMutableArray.h"
 #include "nsContentPermissionHelper.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "nsWindowMemoryReporter.h"
 #include "nsLocation.h"
 #include "mozilla/dom/FontFaceSet.h"
+#include "mozilla/dom/BoxObject.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "mozilla/MediaManager.h"
 #endif // MOZ_MEDIA_NAVIGATOR
 #ifdef MOZ_WEBRTC
 #include "IPeerConnection.h"
 #endif // MOZ_WEBRTC
 
@@ -6942,17 +6943,17 @@ nsDocument::DoNotifyPossibleTitleChange(
   }
 
   // Fire a DOM event for the title change.
   nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
                                       NS_LITERAL_STRING("DOMTitleChanged"),
                                       true, true);
 }
 
-already_AddRefed<nsIBoxObject>
+already_AddRefed<BoxObject>
 nsDocument::GetBoxObjectFor(Element* aElement, ErrorResult& aRv)
 {
   if (!aElement) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsIDocument* doc = aElement->OwnerDoc();
@@ -6969,17 +6970,17 @@ nsDocument::GetBoxObjectFor(Element* aEl
                                     "UseOfGetBoxObjectForWarning");
   }
 
   if (!mBoxObjectTable) {
     mBoxObjectTable = new nsInterfaceHashtable<nsPtrHashKey<nsIContent>, nsPIBoxObject>(6);
   } else {
     nsCOMPtr<nsPIBoxObject> boxObject = mBoxObjectTable->Get(aElement);
     if (boxObject) {
-      return boxObject.forget();
+      return boxObject.forget().downcast<BoxObject>();
     }
   }
 
   int32_t namespaceID;
   nsCOMPtr<nsIAtom> tag = BindingManager()->ResolveTag(aElement, &namespaceID);
 
   nsAutoCString contractID("@mozilla.org/layout/xul-boxobject");
   if (namespaceID == kNameSpaceID_XUL) {
@@ -7010,17 +7011,17 @@ nsDocument::GetBoxObjectFor(Element* aEl
   }
 
   boxObject->Init(aElement);
 
   if (mBoxObjectTable) {
     mBoxObjectTable->Put(aElement, boxObject.get());
   }
 
-  return boxObject.forget();
+  return boxObject.forget().downcast<BoxObject>();
 }
 
 void
 nsDocument::ClearBoxObjectFor(nsIContent* aContent)
 {
   if (mBoxObjectTable) {
     nsPIBoxObject *boxObject = mBoxObjectTable->GetWeak(aContent);
     if (boxObject) {
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -25,18 +25,16 @@
 #include "nsStubDocumentObserver.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIContent.h"
 #include "nsIPrincipal.h"
 #include "nsIParser.h"
 #include "nsBindingManager.h"
 #include "nsInterfaceHashtable.h"
 #include "nsJSThingHashtable.h"
-#include "nsIBoxObject.h"
-#include "nsPIBoxObject.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIURI.h"
 #include "nsScriptLoader.h"
 #include "nsIRadioGroupContainer.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIRequest.h"
 #include "nsILoadGroup.h"
 #include "nsTObserverArray.h"
@@ -90,20 +88,22 @@ class nsChildContentList;
 class nsHTMLStyleSheet;
 class nsHTMLCSSStyleSheet;
 class nsDOMNavigationTiming;
 class nsWindowSizes;
 class nsHtml5TreeOpExecutor;
 class nsDocumentOnStack;
 class nsPointerLockPermissionRequest;
 class nsISecurityConsoleMessage;
+class nsPIBoxObject;
 
 namespace mozilla {
 class EventChainPreVisitor;
 namespace dom {
+class BoxObject;
 class UndoManager;
 struct LifecycleCallbacks;
 class CallbackFunction;
 }
 }
 
 /**
  * Right now our identifier map entries contain information for 'name'
@@ -997,18 +997,20 @@ public:
 
   virtual void BlockOnload();
   virtual void UnblockOnload(bool aFireSync);
 
   virtual void AddStyleRelevantLink(mozilla::dom::Link* aLink);
   virtual void ForgetLink(mozilla::dom::Link* aLink);
 
   void ClearBoxObjectFor(nsIContent* aContent);
-  already_AddRefed<nsIBoxObject> GetBoxObjectFor(mozilla::dom::Element* aElement,
-                                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<mozilla::dom::BoxObject>
+  GetBoxObjectFor(mozilla::dom::Element* aElement,
+                  mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual Element*
     GetAnonymousElementByAttribute(nsIContent* aElement,
                                    nsIAtom* aAttrName,
                                    const nsAString& aAttrValue) const;
 
   virtual Element* ElementFromPointHelper(float aX, float aY,
                                                       bool aIgnoreRootScrollFrame,
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -491,16 +491,17 @@ GK_ATOM(itemref, "itemref")
 GK_ATOM(itemscope, "itemscope")
 GK_ATOM(itemtype, "itemtype")
 GK_ATOM(kbd, "kbd")
 GK_ATOM(noautofocus, "noautofocus")
 GK_ATOM(keepcurrentinview, "keepcurrentinview")
 GK_ATOM(keepobjectsalive, "keepobjectsalive")
 GK_ATOM(key, "key")
 GK_ATOM(keycode, "keycode")
+GK_ATOM(keyschange, "keyschange")
 GK_ATOM(keydown, "keydown")
 GK_ATOM(keygen, "keygen")
 GK_ATOM(keypress, "keypress")
 GK_ATOM(keyset, "keyset")
 GK_ATOM(keysystem, "keysystem")
 GK_ATOM(keytext, "keytext")
 GK_ATOM(keyup, "keyup")
 GK_ATOM(kind, "kind")
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -1243,17 +1243,17 @@ nsScriptLoader::ReadyToExecuteScripts()
     nsScriptLoader* ancestor = doc->ScriptLoader();
     if (!ancestor->SelfReadyToExecuteScripts() &&
         ancestor->AddPendingChildLoader(this)) {
       AddExecuteBlocker();
       return false;
     }
   }
 
-  if (!mDocument->IsMasterDocument()) {
+  if (mDocument && !mDocument->IsMasterDocument()) {
     nsRefPtr<ImportManager> im = mDocument->ImportManager();
     nsRefPtr<ImportLoader> loader = im->Find(mDocument);
     MOZ_ASSERT(loader, "How can we have an import document without a loader?");
 
     // The referring link that counts in the execution order calculation
     // (in spec: flagged as branch)
     nsCOMPtr<nsINode> referrer = loader->GetMainReferrer();
     MOZ_ASSERT(referrer, "There has to be a main referring link for each imports");
--- a/content/base/test/test_bug527896.html
+++ b/content/base/test/test_bug527896.html
@@ -17,18 +17,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 527896 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SimpleTest.expectAssertions(1);
-
 var docWrittenSrcExecuted = false;
 var scriptInsertedSrcExecuted = false;
 
 // the iframe test runs with the HTML5 parser
 
 var iframe = document.getElementsByTagName('iframe')[0];
 iframe.contentWindow.document.open();
 iframe.contentWindow.document.write("<!DOCTYPE html>");
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1159,17 +1159,18 @@ nsresult HTMLMediaElement::LoadResource(
     nsRefPtr<MediaSourceDecoder> decoder = new MediaSourceDecoder(this);
     if (!source->Attach(decoder)) {
       // TODO: Handle failure: run "If the media data cannot be fetched at
       // all, due to network errors, causing the user agent to give up
       // trying to fetch the resource" section of resource fetch algorithm.
       return NS_ERROR_FAILURE;
     }
     mMediaSource = source.forget();
-    nsRefPtr<MediaResource> resource = MediaSourceDecoder::CreateResource();
+    nsRefPtr<MediaResource> resource =
+      MediaSourceDecoder::CreateResource(mMediaSource->GetPrincipal());
     return FinishDecoderSetup(decoder, resource, nullptr, nullptr);
   }
 
   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
 
   // check for a Content Security Policy to pass down to the channel
   // created to load the media content
   nsCOMPtr<nsIChannelPolicy> channelPolicy;
--- a/content/html/content/test/forms/test_meter_element.html
+++ b/content/html/content/test/forms/test_meter_element.html
@@ -16,22 +16,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="visibility: hidden;">
   <form id='f' method='get' target='submit_frame' action='foo'>
     <meter id='m' value=0.5></meter>
   </form>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1);
-} else {
-  SimpleTest.expectAssertions(1);
-}
-
 /** Test for <meter> **/
 
 function checkFormIDLAttribute(aElement)
 {
   is('form' in aElement, false, "<meter> shouldn't have a form attribute");
 }
 
 function checkAttribute(aElement, aAttribute, aNewValue, aExpectedValueForIDL)
--- a/content/html/content/test/test_bug242709.html
+++ b/content/html/content/test/test_bug242709.html
@@ -12,18 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=242709">Mozilla Bug 242709</a>
 <p id="display"></p>
 <div id="content">
 <iframe src="bug242709_iframe.html" id="a"></iframe> 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-SimpleTest.expectAssertions(1);
-
 /** Test for Bug 242709 **/
 
 SimpleTest.waitForExplicitFinish();
 
 var submitted = function() {
   ok(true, "Disabling button after form submission doesn't prevent submitting");
   SimpleTest.finish();
 }
--- a/content/html/content/test/test_bug277890.html
+++ b/content/html/content/test/test_bug277890.html
@@ -12,18 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=277890">Mozilla Bug 277890</a>
 <p id="display"></p>
 <div id="content">
 <iframe src="bug277890_iframe.html" id="a"></iframe> 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-SimpleTest.expectAssertions(1);
-
 /** Test for Bug 277890 **/
 
 SimpleTest.waitForExplicitFinish();
 
 var submitted = function() {
   ok(true, "Disabling button after form submission doesn't prevent submitting");
   SimpleTest.finish();
 }
--- a/content/html/content/test/test_bug523771.html
+++ b/content/html/content/test/test_bug523771.html
@@ -15,22 +15,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 <form action="form_submit_server.sjs" target="target_iframe" id="form"
 method="POST" enctype="multipart/form-data">
   <input id=singleFile name=singleFile type=file>
   <input id=multiFile name=multiFile type=file multiple>
 </form>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1);
-} else {
-  SimpleTest.expectAssertions(1);
-}
-
 var filesToKill = [];
 singleFileInput = document.getElementById('singleFile');
 multiFileInput = document.getElementById('multiFile');
 var input1File = { name: "523771_file1", type: "", body: "file1 contents"};
 var input2Files =
   [{ name: "523771_file2", type: "", body: "second file contents" },
    { name: "523771_file3.txt", type: "text/plain", body: "123456" },
    { name: "523771_file4.html", type: "text/html", body: "<html>content</html>" }
--- a/content/html/content/test/test_iframe_sandbox_inheritance.html
+++ b/content/html/content/test/test_iframe_sandbox_inheritance.html
@@ -9,19 +9,16 @@ Implement HTML5 sandbox attribute for IF
   <title>Test for Bug 341604</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <script type="application/javascript">
 /** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
 /** Inheritance Tests **/
 
-// Assertion failure in docshell/shistory/src/nsSHEntry.cpp (currently line 625).
-// Bug 901876 raised.
-SimpleTest.expectAssertions(1);
 SimpleTest.waitForExplicitFinish();
 
 // A postMessage handler that is used by sandboxed iframes without
 // 'allow-same-origin' to communicate pass/fail back to this main page.
 // It expects to be called with an object like {ok: true/false, desc:
 // <description of the test> which it then forwards to ok().
 window.addEventListener("message", receiveMessage, false);
 
--- a/content/html/content/test/test_iframe_sandbox_navigation.html
+++ b/content/html/content/test/test_iframe_sandbox_navigation.html
@@ -10,17 +10,16 @@ Implement HTML5 sandbox attribute for IF
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <script type="application/javascript">
 /** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
 /** Navigation tests Part 1**/
 
-SimpleTest.expectAssertions(1, 3);
 SimpleTest.waitForExplicitFinish();
 // a postMessage handler that is used by sandboxed iframes without
 // 'allow-same-origin'/other windows to communicate pass/fail back to this main page.
 // it expects to be called with an object like {ok: true/false, desc:
 // <description of the test> which it then forwards to ok()
 window.addEventListener("message", receiveMessage, false);
 
 var testPassesReceived = 0;
--- a/content/html/document/test/test_bug448564.html
+++ b/content/html/document/test/test_bug448564.html
@@ -15,18 +15,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   <iframe src="bug448564-iframe-2.html"></iframe>
   <iframe src="bug448564-iframe-3.html"></iframe>
 </p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-SimpleTest.expectAssertions(3);
-
 /** Test for Bug 448564 **/
 
 /**
  * The three iframes are going to be loaded with some dirty constructed forms.
  * Each of them will be submitted before the load event and a SJS will replace
  * the frame content with the query string.
  * Then, on the load event, our test file will check the content of each iframes
  * and check if the query string were correctly formatted (implying that all
--- a/content/html/document/test/test_bug478251.html
+++ b/content/html/document/test/test_bug478251.html
@@ -12,18 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=478251">Mozilla Bug 478251</a>
 <p id="display"><iframe id="t"></iframe></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-SimpleTest.expectAssertions(9, 10);
-
 /** Test for Bug 478251 **/
 var doc = $("t").contentDocument;
 doc.open();
 doc.write();
 doc.close();
 is(doc.documentElement.textContent, "", "Writing || failed");
 
 doc.open();
--- a/content/media/eme/CDMCallbackProxy.cpp
+++ b/content/media/eme/CDMCallbackProxy.cpp
@@ -267,28 +267,48 @@ CDMCallbackProxy::SessionError(const nsC
 }
 
 void
 CDMCallbackProxy::KeyIdUsable(const nsCString& aSessionId,
                               const nsTArray<uint8_t>& aKeyId)
 {
   MOZ_ASSERT(mProxy->IsOnGMPThread());
 
-  CDMCaps::AutoLock caps(mProxy->Capabilites());
-  caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+  bool keysChange = false;
+  {
+    CDMCaps::AutoLock caps(mProxy->Capabilites());
+    keysChange = caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+  }
+  if (keysChange) {
+    nsRefPtr<nsIRunnable> task;
+    task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
+                                                 &CDMProxy::OnKeysChange,
+                                                 NS_ConvertUTF8toUTF16(aSessionId));
+    NS_DispatchToMainThread(task);
+  }
 }
 
 void
 CDMCallbackProxy::KeyIdNotUsable(const nsCString& aSessionId,
                                  const nsTArray<uint8_t>& aKeyId)
 {
   MOZ_ASSERT(mProxy->IsOnGMPThread());
 
-  CDMCaps::AutoLock caps(mProxy->Capabilites());
-  caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+  bool keysChange = false;
+  {
+    CDMCaps::AutoLock caps(mProxy->Capabilites());
+    keysChange = caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
+  }
+  if (keysChange) {
+    nsRefPtr<nsIRunnable> task;
+    task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
+                                                 &CDMProxy::OnKeysChange,
+                                                 NS_ConvertUTF8toUTF16(aSessionId));
+    NS_DispatchToMainThread(task);
+  }
 }
 
 void
 CDMCallbackProxy::SetCaps(uint64_t aCaps)
 {
   MOZ_ASSERT(mProxy->IsOnGMPThread());
 
   CDMCaps::AutoLock caps(mProxy->Capabilites());
--- a/content/media/eme/CDMCaps.cpp
+++ b/content/media/eme/CDMCaps.cpp
@@ -83,53 +83,63 @@ CDMCaps::AutoLock::IsKeyUsable(const Cen
   for (size_t i = 0; i < keys.Length(); i++) {
     if (keys[i].mId == aKeyId) {
       return true;
     }
   }
   return false;
 }
 
-void
+bool
 CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
                                 const nsString& aSessionId)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
-  mData.mUsableKeyIds.AppendElement(UsableKey(aKeyId, aSessionId));
+  UsableKey key(aKeyId, aSessionId);
+  if (mData.mUsableKeyIds.Contains(key)) {
+    return false;
+  }
+  mData.mUsableKeyIds.AppendElement(key);
   auto& waiters = mData.mWaitForKeys;
   size_t i = 0;
   while (i < waiters.Length()) {
     auto& w = waiters[i];
     if (w.mKeyId == aKeyId) {
       if (waiters[i].mTarget) {
         EME_LOG("SetKeyUsable() notified waiter.");
         w.mTarget->Dispatch(w.mContinuation, NS_DISPATCH_NORMAL);
       } else {
         w.mContinuation->Run();
       }
       waiters.RemoveElementAt(i);
     } else {
       i++;
     }
   }
+  return true;
 }
 
-void
+bool
 CDMCaps::AutoLock::SetKeyUnusable(const CencKeyId& aKeyId,
                                   const nsString& aSessionId)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
+  UsableKey key(aKeyId, aSessionId);
+  if (!mData.mUsableKeyIds.Contains(key)) {
+    return false;
+  }
   auto& keys = mData.mUsableKeyIds;
   for (size_t i = 0; i < keys.Length(); i++) {
     if (keys[i].mId == aKeyId &&
         keys[i].mSessionId == aSessionId) {
       keys.RemoveElementAt(i);
       break;
     }
   }
+  return true;
 }
 
 void
 CDMCaps::AutoLock::CallWhenKeyUsable(const CencKeyId& aKey,
                                      nsIRunnable* aContinuation,
                                      nsIThread* aTarget)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
--- a/content/media/eme/CDMCaps.h
+++ b/content/media/eme/CDMCaps.h
@@ -33,18 +33,23 @@ public:
     ~AutoLock();
 
     // Returns true if the capabilities of the CDM are known, i.e. they have
     // been reported by the CDM to Gecko.
     bool AreCapsKnown();
 
     bool IsKeyUsable(const CencKeyId& aKeyId);
 
-    void SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
-    void SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
+    // Returns true if setting this key usable results in the usable keys
+    // changing for this session, i.e. the key was not previously marked usable.
+    bool SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
+
+    // Returns true if setting this key unusable results in the usable keys
+    // changing for this session, i.e. the key was previously marked usable.
+    bool SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
 
     void DropKeysForSession(const nsAString& aSessionId);
     void GetUsableKeysForSession(const nsAString& aSessionId,
                                  nsTArray<CencKeyId>& aOutKeyIds);
 
     // Sets the capabilities of the CDM. aCaps is the logical OR of the
     // GMP_EME_CAP_* flags from gmp-decryption.h.
     void SetCaps(uint64_t aCaps);
@@ -94,16 +99,21 @@ private:
               const nsString& aSessionId)
       : mId(aId)
       , mSessionId(aSessionId)
     {}
     UsableKey(const UsableKey& aOther)
       : mId(aOther.mId)
       , mSessionId(aOther.mSessionId)
     {}
+    bool operator==(const UsableKey& aOther) const {
+      return mId == aOther.mId &&
+             mSessionId == aOther.mSessionId;
+    };
+
     CencKeyId mId;
     nsString mSessionId;
   };
   nsTArray<UsableKey> mUsableKeyIds;
 
   nsTArray<WaitForKeys> mWaitForKeys;
 
   nsTArray<nsRefPtr<nsIRunnable>> mWaitForCaps;
--- a/content/media/eme/CDMProxy.cpp
+++ b/content/media/eme/CDMProxy.cpp
@@ -421,16 +421,29 @@ CDMProxy::OnSessionMessage(const nsAStri
   }
   nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
   if (session) {
     session->DispatchKeyMessage(aMessage, aDestinationURL);
   }
 }
 
 void
+CDMProxy::OnKeysChange(const nsAString& aSessionId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mKeys.IsNull()) {
+    return;
+  }
+  nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
+  if (session) {
+    session->DispatchKeysChange();
+  }
+}
+
+void
 CDMProxy::OnExpirationChange(const nsAString& aSessionId,
                              GMPTimestamp aExpiryTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_WARNING("CDMProxy::OnExpirationChange() not implemented");
 }
 
 void
--- a/content/media/eme/CDMProxy.h
+++ b/content/media/eme/CDMProxy.h
@@ -157,16 +157,19 @@ public:
                      GMPErr aResult,
                      const nsTArray<uint8_t>& aDecryptedData);
 
   // GMP thread only.
   void gmp_Terminated();
 
   CDMCaps& Capabilites();
 
+  // Main thread only.
+  void OnKeysChange(const nsAString& aSessionId);
+
 #ifdef DEBUG
   bool IsOnGMPThread();
 #endif
 
 private:
 
   struct InitData {
     uint32_t mPromiseId;
--- a/content/media/eme/MediaKeySession.cpp
+++ b/content/media/eme/MediaKeySession.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/dom/MediaKeySession.h"
 #include "mozilla/dom/MediaKeyError.h"
 #include "mozilla/dom/MediaKeyMessageEvent.h"
 #include "mozilla/dom/MediaEncryptedEvent.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Move.h"
+#include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaKeySession,
                                    DOMEventTargetHelper,
                                    mMediaKeyError,
                                    mKeys,
@@ -279,10 +280,29 @@ void
 MediaKeySession::DispatchKeyError(uint32_t aSystemCode)
 {
   RefPtr<MediaKeyError> event(new MediaKeyError(this, aSystemCode));
   nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(this, event);
   asyncDispatcher->PostDOMEvent();
 }
 
+void
+MediaKeySession::DispatchKeysChange()
+{
+  if (IsClosed()) {
+    return;
+  }
+  DebugOnly<nsresult> rv =
+    nsContentUtils::DispatchTrustedEvent(mKeys->GetOwnerDoc(),
+                                         this,
+                                         NS_LITERAL_STRING("keyschange"),
+                                         false,
+                                         false);
+#ifdef DEBUG
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to dispatch keyschange event");
+  }
+#endif
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/media/eme/MediaKeySession.h
+++ b/content/media/eme/MediaKeySession.h
@@ -79,16 +79,18 @@ public:
 
   already_AddRefed<Promise> GetUsableKeyIds(ErrorResult& aRv);
 
   void DispatchKeyMessage(const nsTArray<uint8_t>& aMessage,
                           const nsAString& aURL);
 
   void DispatchKeyError(uint32_t system_code);
 
+  void DispatchKeysChange();
+
   void OnClosed();
 
   bool IsClosed() const;
 
 private:
   ~MediaKeySession();
 
   nsRefPtr<Promise> mClosed;
--- a/content/media/eme/MediaKeys.cpp
+++ b/content/media/eme/MediaKeys.cpp
@@ -586,10 +586,16 @@ CopyArrayBufferViewOrArrayBufferData(con
     bufferview.ComputeLengthAndData();
     aOutData.AppendElements(bufferview.Data(), bufferview.Length());
   } else {
     return false;
   }
   return true;
 }
 
+nsIDocument*
+MediaKeys::GetOwnerDoc() const
+{
+  return mElement ? mElement->OwnerDoc() : nullptr;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/media/eme/MediaKeys.h
+++ b/content/media/eme/MediaKeys.h
@@ -117,16 +117,20 @@ public:
 
   // Returns true if this MediaKeys has been bound to a media element.
   bool IsBoundToMediaElement() const;
 
   // Return NS_OK if the principals are the same as when the MediaKeys
   // was created, failure otherwise.
   nsresult CheckPrincipals();
 
+  // Returns a pointer to the bound media element's owner doc.
+  // If we're not bound, this returns null.
+  nsIDocument* GetOwnerDoc() const;
+
 private:
 
   static bool IsTypeSupported(const nsAString& aKeySystem,
                               const Optional<nsAString>& aInitDataType = Optional<nsAString>(),
                               const Optional<nsAString>& aContentType = Optional<nsAString>());
 
   bool IsInPrivateBrowsing();
   already_AddRefed<Promise> Init(ErrorResult& aRv);
--- a/content/media/mediasource/MediaSource.cpp
+++ b/content/media/mediasource/MediaSource.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "mozilla/mozalloc.h"
 #include "nsContentTypeParser.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsIRunnable.h"
+#include "nsIScriptObjectPrincipal.h"
 #include "nsPIDOMWindow.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
 
 struct JSContext;
 class JSObject;
 
@@ -389,22 +390,29 @@ MediaSource::GetBuffered(TimeRanges* aBu
 
   MSE_DEBUG("MediaSource(%p)::GetBuffered ranges=%s", this, DumpTimeRanges(intersectionRanges).get());
 }
 
 MediaSource::MediaSource(nsPIDOMWindow* aWindow)
   : DOMEventTargetHelper(aWindow)
   , mDuration(UnspecifiedNaN<double>())
   , mDecoder(nullptr)
+  , mPrincipal(nullptr)
   , mReadyState(MediaSourceReadyState::Closed)
   , mFirstSourceBufferInitialized(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mSourceBuffers = new SourceBufferList(this);
   mActiveSourceBuffers = new SourceBufferList(this);
+
+  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
+  if (sop) {
+    mPrincipal = sop->GetPrincipal();
+  }
+
   MSE_API("MediaSource(%p)::MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p",
           this, aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get());
 }
 
 void
 MediaSource::SetReadyState(MediaSourceReadyState aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/content/media/mediasource/MediaSource.h
+++ b/content/media/mediasource/MediaSource.h
@@ -80,16 +80,21 @@ public:
   void SetReadyState(MediaSourceReadyState aState);
 
  // Used by SourceBuffer to call CreateSubDecoder.
   MediaSourceDecoder* GetDecoder()
   {
     return mDecoder;
   }
 
+  nsIPrincipal* GetPrincipal()
+  {
+    return mPrincipal;
+  }
+
   // Called by SourceBuffers to notify this MediaSource that data has
   // been evicted from the buffered data. The start and end times
   // that were evicted are provided.
   void NotifyEvicted(double aStart, double aEnd);
 
   // Queue InitializationEvent to run on the main thread.  Called when a
   // SourceBuffer has an initialization segment appended, but only
   // dispatched the first time (using mFirstSourceBufferInitialized).
@@ -123,16 +128,18 @@ private:
 
   double mDuration;
 
   nsRefPtr<SourceBufferList> mSourceBuffers;
   nsRefPtr<SourceBufferList> mActiveSourceBuffers;
 
   nsRefPtr<MediaSourceDecoder> mDecoder;
 
+  nsRefPtr<nsIPrincipal> mPrincipal;
+
   MediaSourceReadyState mReadyState;
 
   bool mFirstSourceBufferInitialized;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(MediaSource, MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)
 
 } // namespace dom
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -102,19 +102,19 @@ MediaSourceDecoder::Shutdown()
   }
   // Kick WaitForData out of its slumber.
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mon.NotifyAll();
 }
 
 /*static*/
 already_AddRefed<MediaResource>
-MediaSourceDecoder::CreateResource()
+MediaSourceDecoder::CreateResource(nsIPrincipal* aPrincipal)
 {
-  return nsRefPtr<MediaResource>(new MediaSourceResource()).forget();
+  return nsRefPtr<MediaResource>(new MediaSourceResource(aPrincipal)).forget();
 }
 
 void
 MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
 {
   MOZ_ASSERT(!mMediaSource && !mDecoderStateMachine && NS_IsMainThread());
   mMediaSource = aMediaSource;
 }
--- a/content/media/mediasource/MediaSourceDecoder.h
+++ b/content/media/mediasource/MediaSourceDecoder.h
@@ -36,17 +36,17 @@ public:
 
   virtual MediaDecoder* Clone() MOZ_OVERRIDE;
   virtual MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
   virtual nsresult Load(nsIStreamListener**, MediaDecoder*) MOZ_OVERRIDE;
   virtual nsresult GetSeekable(dom::TimeRanges* aSeekable) MOZ_OVERRIDE;
 
   virtual void Shutdown() MOZ_OVERRIDE;
 
-  static already_AddRefed<MediaResource> CreateResource();
+  static already_AddRefed<MediaResource> CreateResource(nsIPrincipal* aPrincipal = nullptr);
 
   void AttachMediaSource(dom::MediaSource* aMediaSource);
   void DetachMediaSource();
 
   already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
   void AddTrackBuffer(TrackBuffer* aTrackBuffer);
   void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
   void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
--- a/content/media/mediasource/MediaSourceResource.h
+++ b/content/media/mediasource/MediaSourceResource.h
@@ -21,22 +21,22 @@ extern PRLogModuleInfo* GetMediaSourceAP
 
 #define UNIMPLEMENTED() MSE_DEBUG("MediaSourceResource(%p): UNIMPLEMENTED FUNCTION at %s:%d", this, __FILE__, __LINE__)
 
 namespace mozilla {
 
 class MediaSourceResource MOZ_FINAL : public MediaResource
 {
 public:
-  MediaSourceResource() {}
+  MediaSourceResource(nsIPrincipal* aPrincipal = nullptr)
+    : mPrincipal(aPrincipal) {}
 
   virtual nsresult Close() MOZ_OVERRIDE { return NS_OK; }
   virtual void Suspend(bool aCloseImmediately) MOZ_OVERRIDE { UNIMPLEMENTED(); }
   virtual void Resume() MOZ_OVERRIDE { UNIMPLEMENTED(); }
-  virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() MOZ_OVERRIDE { UNIMPLEMENTED(); return nullptr; }
   virtual bool CanClone() MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
   virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder) MOZ_OVERRIDE { UNIMPLEMENTED(); return nullptr; }
   virtual void SetReadMode(MediaCacheStream::ReadMode aMode) MOZ_OVERRIDE { UNIMPLEMENTED(); }
   virtual void SetPlaybackRate(uint32_t aBytesPerSecond) MOZ_OVERRIDE  { UNIMPLEMENTED(); }
   virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
   virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
   virtual nsresult Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
   virtual int64_t Tell() MOZ_OVERRIDE { UNIMPLEMENTED(); return -1; }
@@ -47,16 +47,21 @@ public:
   virtual int64_t GetNextCachedData(int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return -1; }
   virtual int64_t GetCachedDataEnd(int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return -1; }
   virtual bool IsDataCachedToEndOfResource(int64_t aOffset) MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
   virtual bool IsSuspendedByCache() MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
   virtual bool IsSuspended() MOZ_OVERRIDE { UNIMPLEMENTED(); return false; }
   virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
   virtual nsresult Open(nsIStreamListener** aStreamListener) MOZ_OVERRIDE { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
 
+  virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() MOZ_OVERRIDE
+  {
+    return nsRefPtr<nsIPrincipal>(mPrincipal).forget();
+  }
+
   virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) MOZ_OVERRIDE
   {
     UNIMPLEMENTED();
     aRanges.AppendElement(MediaByteRange(0, GetLength()));
     return NS_OK;
   }
 
   virtual bool IsTransportSeekable() MOZ_OVERRIDE { return true; }
@@ -71,16 +76,17 @@ private:
     return size;
   }
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
+  nsRefPtr<nsIPrincipal> mPrincipal;
   const nsCString mType;
 };
 
 } // namespace mozilla
 
 #undef UNIMPLEMENTED
 
 #endif /* MOZILLA_MEDIASOURCERESOURCE_H_ */
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/1080986.html
@@ -0,0 +1,3 @@
+<html>
+<audio autoplay src="1080986.wav"></audio>
+</html>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b96c59b7ec2ecdc5033904eb9ceb779adb05d154
GIT binary patch
literal 592
zc$^hcT}YE*6n@_CCl^^QFDjWt+TTUA#c*?Y5lw40`qwd67vdo7rmmVIQK3Yj-2@s~
zS6vi{8Fi6el#pnV&6El;gCHzpHODj!o!_?adwM;G1Lr(E&-vlh1_ObB0@VA%N1HCk
zb`}8;(*LNyrvgBMT_Pufbs<SY@KoS*ur3fPT*IO*O`dY6`=GNN7oxGKq~crVz{*o|
zvo>P2WoMOp`h#pNzsy7VN~KG4s)wz(c}ek#Au)j^vzdMRO)Zo=k79Ff^^Nt#c%Mz-
zy0V>RqC!m@y~bT%nVLrXI)_aae*L*x%iC-bhG-QXe933LrCrprc^7^PCla<!J-@Ok
z7uS1v#p=en+y}K)+{uoLX_T5jxJ?_^1Gxsq)h%XHnIO1Fn^GO9qEBgOmpN!u8}nSn
z8RLGYSILMQ`8KNf%qOBpq*yGP(PP<#S16X7%VG!{;KYD6LA$7Cx4FmxG%~{oPGSs8
zEMpi6eCJt&M3TSQh$Fa)esr>rbErXtLo7s+Uc6=tkHL%Me8e2TQo(w3@GqlC(S{<7
z@|r~JF-Z@0;4$Z!<S^gSl<XO<*(<5p2p4Lx8;dNFznh^071)afPV*nDunTEg+=@Y|
z+lLYq;3NCFOoOvb@U86kkRvi5<_k_qpJZBAI`Uj$DJo@O7u?tnkJS1RMgt=9h8nrG
QPev(BF34@h`CHEY54@=vF#rGn
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -69,12 +69,13 @@ load 986901.html
 load 990794.html
 load 1015662.html
 skip-if(Android||B2G) test-pref(media.navigator.permission.disabled,true) load 1028458.html # bug 1048863
 load buffer-source-ended-1.html
 HTTP load media-element-source-seek-1.html
 load offline-buffer-source-ended-1.html
 load oscillator-ended-1.html
 load oscillator-ended-2.html
+load 1080986.html
 include ../../mediasource/test/crashtests/crashtests.list
 
 # This needs to run at the end to avoid leaking busted state into other tests.
 skip-if(winWidget) load 691096-1.html
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -644,29 +644,28 @@ var gEMETests = [
     keys: {
       // "keyid" : "key"
       "7e571d017e571d017e571d017e571d01" : "7e5711117e5711117e5711117e571111",
       "7e571d027e571d027e571d027e571d02" : "7e5722227e5722227e5722227e572222",
     },
     sessionType:"temporary",
     duration:0.47
   },
-  // XXX Bug 1082239
-  //{
-  //  name:"gizmo-frag-cencinit.mp4",
-  //  fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
-  //  type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
-  //  keys: {
-  //    // "keyid" : "key"
-  //    "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
-  //    "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
-  //  },
-  //  sessionType:"temporary",
-  //  duration:2.00,
-  //},
+  {
+    name:"gizmo-frag-cencinit.mp4",
+    fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
+    type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
+    keys: {
+      // "keyid" : "key"
+      "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+      "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+    },
+    sessionType:"temporary",
+    duration:2.00,
+  },
 ];
 
 function checkMetadata(msg, e, test) {
   if (test.width) {
     is(e.videoWidth, test.width, msg + " video width");
   }
   if (test.height) {
     is(e.videoHeight, test.height, msg + " video height");
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -472,16 +472,17 @@ skip-if = buildapp == 'b2g' # bug 102168
 [test_texttrackcue.html]
 [test_texttracklist.html]
 [test_texttrackregion.html]
 [test_timeupdate_small_files.html]
 [test_trackelementevent.html]
 [test_trackevent.html]
 [test_unseekable.html]
 [test_video_to_canvas.html]
+[test_video_in_audio_element.html]
 [test_videoDocumentTitle.html]
 [test_VideoPlaybackQuality.html]
 [test_VideoPlaybackQuality_disabled.html]
 [test_volume.html]
 [test_vttparser.html]
 [test_webvtt_disabled.html]
 
 # The tests below contain backend-specific tests. Write backend independent
--- a/content/media/test/test_encryptedMediaExtensions.html
+++ b/content/media/test/test_encryptedMediaExtensions.html
@@ -148,16 +148,35 @@ function PlayTest(test, elem)
     return;
   }
 
   // This file isn't fragmented; set the media source normally.
   elem.src = test.name;
   elem.play();
 }
 
+function KeysChangeFunc(session, keys) {
+  session.keyIdsReceived = [];
+  for (var keyid in keys) {
+    info("Set " + keyid + " to false in session.keyIdsReceived");
+    session.keyIdsReceived[keyid] = false;
+  }
+  return function(ev) {
+    var session = ev.target;
+    session.gotKeysChanged = true;
+    session.getUsableKeyIds().then(function(keyIds) {
+      for (var k = 0; k < keyIds.length; k++) {
+        var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
+        ok(kid in session.keyIdsReceived, "session.keyIdsReceived contained " + kid + " as expected.");
+        session.keyIdsReceived[kid] = true;
+      }
+    }, bail("Failed to get keyIds"));
+  }
+}
+
 function startTest(test, token)
 {
   manager.started(test._token);
 
   var v = document.createElement("video");
   var gotEncrypted = false;
   var gotPlaying = false;
 
@@ -165,24 +184,27 @@ function startTest(test, token)
     gotEncrypted = true;
 
     info(token + " got encrypted event");
     ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
        token + " MediaKeys should support this keysystem");
 
     MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
       info(token + " created MediaKeys object ok");
+      mediaKeys.sessions = [];
       return v.setMediaKeys(mediaKeys);
     }, bail("failed to create MediaKeys object")).then(function() {
       info(token + " set MediaKeys on <video> element ok");
 
       ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
          "MediaKeys should still support keysystem after CDM created...");
 
       var session = v.mediaKeys.createSession(test.sessionType);
+      v.mediaKeys.sessions.push(session);
+      session.addEventListener("keyschange", KeysChangeFunc(session, test.keys), false);
       session.addEventListener("message", UpdateSessionFunc(test));
       session.generateRequest(ev.initDataType, ev.initData).then(function() {
       }, bail(token + " Failed to initialise MediaKeySession"));
 
     }, bail(token + " Failed to set MediaKeys on <video> element"));
   });
 
   v.addEventListener("playing", function () { gotPlaying = true; });
@@ -193,16 +215,27 @@ function startTest(test, token)
 
     ok(gotEncrypted, token + " encrypted event should have fired");
     ok(gotPlaying, token + " playing event should have fired");
 
     ok(Math.abs(test.duration - v.duration) < 0.1,
        token + " Duration of video should be corrrect");
     ok(Math.abs(test.duration - v.currentTime) < 0.1,
        token + " Current time should be same as duration");
+    // Verify all sessions had all keys went sent the to the CDM usable, and thus
+    // that we received keyschange event(s).
+    var sessions = v.mediaKeys.sessions;
+    is(sessions.length, 1, "should have 1 session");
+    for (var i = 0; i < sessions.length; i++) {
+      var session = sessions[i];
+      ok(session.gotKeysChanged, "Should have received at least one keychange event");
+      for (var kid in session.keyIdsReceived) {
+        ok(session.keyIdsReceived[kid], "key with id " + kid + " was usable as expected");
+      }
+    }
   });
 
   v.addEventListener("error", bail(token + " got error event"));
 
   PlayTest(test, v);
 }
 
 function testIsTypeSupported()
--- a/content/media/test/test_imagecapture.html
+++ b/content/media/test/test_imagecapture.html
@@ -33,16 +33,17 @@ function gcTest(track) {
       };
       imageCapture.onerror = function(error) {
         ok(false, "takePhoto failure in gc testing");
         reject();
       };
 
       imageCapture.takePhoto();
     }
+    info("Call gc ");
     SpecialPowers.gc();
   });
 }
 
 // Continue calling takePhoto() in rapid succession.
 function rapidTest(track) {
   return new Promise(function(resolve, reject) {
     var imageCapture = new ImageCapture(track);
@@ -106,18 +107,30 @@ function trackTest(track) {
 
     track.enabled = false;
     imageCapture.takePhoto()
   });
 }
 
 function init() {
   return new Promise(function(resolve, reject) {
+    var constraints;
+    if (SpecialPowers.Services.appinfo.widgetToolkit == "gonk") {
+      info("B2G ImageCapture test");
+      // Reduce repeat count due to b2g emulator is very slow.
+      repeat = 20;
+      // Use gonk camera, MedieEngine will be the backend of ImageCapture.
+      constraints = {video: true};
+    } else {
+      // use fake camera, MediaStreamGraph will be the backend of ImageCapture.
+      constraints = {video: true, fake: true}
+    }
+
     window.navigator.mozGetUserMedia(
-      {video: true, fake: true},
+      constraints,
       function(stream) {
         var track = stream.getVideoTracks()[0];
         resolve(track);
       },
       function(err) {
         reject(err);
       }
     );
@@ -132,20 +145,21 @@ function start() {
     info("ImageCapture blob test.");
     return blobTest(track);
   }).then(function(track) {
     info("ImageCapture rapid takePhoto() test.");
     return rapidTest(track);
   }).then(function(track) {
     info("ImageCapture multiple instances test.");
     return gcTest(track);
-  }).then(function() {
-    SimpleTest.finish();
-  });
+  }).then(SimpleTest.finish);
 }
 
+SimpleTest.requestCompleteLog();
 SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({"set": [["dom.imagecapture.enabled", true]]}, start);
 
+SpecialPowers.pushPrefEnv({"set": [["dom.imagecapture.enabled", true],
+                                  ["media.navigator.permission.disabled", true]
+                                  ]}, start);
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_video_in_audio_element.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1060896
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1060896</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="manifest.js"></script>
+  <script type="application/javascript">
+
+  /**
+   * Test for Bug 1060896; tests that loading a video inside an audio element works.
+   **/
+
+  var manager = new MediaTestManager;
+   
+  function ended(event) {
+    var a = event.target;
+    removeNodeAndSource(a);
+    manager.finished(a.token);
+  }
+   
+  function initTest(test, token) {
+    var a = document.createElement('audio');
+    a.token = token;
+    manager.started(token);
+    a.autoplay = true;
+    
+    a.addEventListener("ended", ended, false);
+
+    a.src = test.name;
+  }
+
+  var videos = gSmallTests.filter(function(x){return /^video/.test(x.type);});
+  
+  manager.runTests(videos, initTest);
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1060896">Mozilla Bug 1060896</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/media/wave/WaveReader.cpp
+++ b/content/media/wave/WaveReader.cpp
@@ -546,27 +546,27 @@ WaveReader::LoadListChunk(uint32_t aChun
   // List chunks are always word (two byte) aligned.
   NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0,
                     "LoadListChunk called with unaligned resource");
 
   static const unsigned int MAX_CHUNK_SIZE = 1 << 16;
   static_assert(uint64_t(MAX_CHUNK_SIZE) < UINT_MAX / sizeof(char),
                 "MAX_CHUNK_SIZE too large for enumerator.");
 
-  if (aChunkSize > MAX_CHUNK_SIZE) {
+  if (aChunkSize > MAX_CHUNK_SIZE || aChunkSize < 4) {
     return false;
   }
 
   nsAutoArrayPtr<char> chunk(new char[aChunkSize]);
   if (!ReadAll(chunk.get(), aChunkSize)) {
     return false;
   }
 
   static const uint32_t INFO_LIST_MAGIC = 0x494e464f;
-  const char *p = chunk.get();
+  const char* p = chunk.get();
   if (ReadUint32BE(&p) != INFO_LIST_MAGIC) {
     return false;
   }
 
   const waveIdToName ID_TO_NAME[] = {
     { 0x49415254, NS_LITERAL_CSTRING("artist") },   // IART
     { 0x49434d54, NS_LITERAL_CSTRING("comments") }, // ICMT
     { 0x49474e52, NS_LITERAL_CSTRING("genre") },    // IGNR
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -68,17 +68,17 @@
 #include "nsXULControllers.h"
 #include "nsIBoxObject.h"
 #include "nsPIBoxObject.h"
 #include "XULDocument.h"
 #include "nsXULPopupListener.h"
 #include "nsRuleWalker.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsCSSParser.h"
-#include "nsIListBoxObject.h"
+#include "ListBoxObject.h"
 #include "nsContentUtils.h"
 #include "nsContentList.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/MouseEvents.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsPIDOMWindow.h"
 #include "nsJSPrincipals.h"
 #include "nsDOMAttributeMap.h"
@@ -104,16 +104,17 @@
 #include "nsXBLBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIDOMXULCommandEvent.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsICSSDeclaration.h"
 
 #include "mozilla/dom/XULElementBinding.h"
+#include "mozilla/dom/BoxObject.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
 uint32_t             nsXULPrototypeAttribute::gNumElements;
 uint32_t             nsXULPrototypeAttribute::gNumAttributes;
 uint32_t             nsXULPrototypeAttribute::gNumCacheTests;
@@ -1500,17 +1501,17 @@ nsXULElement::GetControllers(ErrorResult
 NS_IMETHODIMP
 nsXULElement::GetBoxObject(nsIBoxObject** aResult)
 {
     ErrorResult rv;
     *aResult = GetBoxObject(rv).take();
     return rv.ErrorCode();
 }
 
-already_AddRefed<nsIBoxObject>
+already_AddRefed<BoxObject>
 nsXULElement::GetBoxObject(ErrorResult& rv)
 {
     // XXX sXBL/XBL2 issue! Owner or current document?
     return OwnerDoc()->GetBoxObjectFor(this, rv);
 }
 
 // Methods for setting/getting attributes from nsIDOMXULElement
 #define NS_IMPL_XUL_STRING_ATTR(_method, _atom)                     \
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -21,17 +21,16 @@
 #include "nsIControllers.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIRDFCompositeDataSource.h"
 #include "nsIRDFResource.h"
 #include "nsIURI.h"
 #include "nsIXULTemplateBuilder.h"
-#include "nsIBoxObject.h"
 #include "nsLayoutCID.h"
 #include "nsAttrAndChildArray.h"
 #include "nsGkAtoms.h"
 #include "nsAutoPtr.h"
 #include "nsStyledElement.h"
 #include "nsIFrameLoader.h"
 #include "nsFrameLoader.h"
 #include "mozilla/dom/DOMRect.h"
@@ -49,16 +48,19 @@ class nsXULPrototypeNode;
 typedef nsTArray<nsRefPtr<nsXULPrototypeNode> > nsPrototypeArray;
 
 namespace mozilla {
 class EventChainPreVisitor;
 class EventListenerManager;
 namespace css {
 class StyleRule;
 }
+namespace dom {
+class BoxObject;
+}
 }
 
 namespace JS {
 class SourceBufferHolder;
 }
 
 ////////////////////////////////////////////////////////////////////////
 
@@ -582,17 +584,17 @@ public:
     bool AllowEvents() const
     {
         return BoolAttrIsTrue(nsGkAtoms::allowevents);
     }
     already_AddRefed<nsIRDFCompositeDataSource> GetDatabase();
     already_AddRefed<nsIXULTemplateBuilder> GetBuilder();
     already_AddRefed<nsIRDFResource> GetResource(mozilla::ErrorResult& rv);
     nsIControllers* GetControllers(mozilla::ErrorResult& rv);
-    already_AddRefed<nsIBoxObject> GetBoxObject(mozilla::ErrorResult& rv);
+    already_AddRefed<mozilla::dom::BoxObject> GetBoxObject(mozilla::ErrorResult& rv);
     void Focus(mozilla::ErrorResult& rv);
     void Blur(mozilla::ErrorResult& rv);
     void Click(mozilla::ErrorResult& rv);
     // The XPCOM DoCommand never fails, so it's OK for us.
     already_AddRefed<nsINodeList>
       GetElementsByAttribute(const nsAString& aAttribute,
                              const nsAString& aValue);
     already_AddRefed<nsINodeList>
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -39,16 +39,17 @@
 #include "nsXMLContentSink.h"
 #include "nsXULContentSink.h"
 #include "nsXULContentUtils.h"
 #include "nsIXULOverlayProvider.h"
 #include "nsIStringEnumerator.h"
 #include "nsNetUtil.h"
 #include "nsParserCIID.h"
 #include "nsPIBoxObject.h"
+#include "mozilla/dom/BoxObject.h"
 #include "nsXPIDLString.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsXULCommandDispatcher.h"
 #include "nsXULElement.h"
 #include "prlog.h"
 #include "rdf.h"
 #include "nsIFrame.h"
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4190,17 +4190,17 @@ nsDocShell::GetChildSHEntry(int32_t aChi
 
 NS_IMETHODIMP
 nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
                             int32_t aChildOffset, uint32_t loadType,
                             bool aCloneChildren)
 {
     nsresult rv;
 
-    if (mLSHE && loadType != LOAD_PUSHSTATE) {
+    if (mLSHE && loadType != LOAD_PUSHSTATE && !aCloneRef) {
         /* You get here if you are currently building a 
          * hierarchy ie.,you just visited a frameset page
          */
         nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
         if (container) {
             rv = container->AddChild(aNewEntry, aChildOffset);
         }
     }
--- a/docshell/test/test_bug580069.html
+++ b/docshell/test/test_bug580069.html
@@ -11,18 +11,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=580069">Mozilla Bug 580069</a>
 
 <iframe id='iframe' src='file_bug580069_1.html'></iframe>
 
 <script type="application/javascript">
 
-SimpleTest.expectAssertions(1);
-
 SimpleTest.waitForExplicitFinish();
 
 var iframe = document.getElementById('iframe');
 var iframeCw = iframe.contentWindow;
 
 // Called when file_bug580069_1.html loads.
 function page1Load() {
   // This should cause us to load file 2.
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -81,17 +81,16 @@
 #include "nsIDOMCSSSupportsRule.h"
 #include "nsIDOMMozCSSKeyframeRule.h"
 #include "nsIDOMMozCSSKeyframesRule.h"
 #include "nsIDOMCSSCounterStyleRule.h"
 #include "nsIDOMCSSPageRule.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIControllers.h"
-#include "nsIBoxObject.h"
 #ifdef MOZ_XUL
 #include "nsITreeSelection.h"
 #include "nsITreeContentView.h"
 #include "nsITreeView.h"
 #include "nsIXULTemplateBuilder.h"
 #include "nsITreeColumns.h"
 #endif
 #include "nsIDOMXPathNSResolver.h"
@@ -246,18 +245,16 @@ static nsDOMClassInfoData sClassInfoData
 
   // XUL classes
 #ifdef MOZ_XUL
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCommandDispatcher, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControllers, nsNonDOMObjectSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(BoxObject, nsDOMGenericSH,
-                                      DEFAULT_SCRIPTABLE_FLAGS)
 #ifdef MOZ_XUL
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeSelection, nsDOMGenericSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeContentView, nsDOMGenericSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
 #ifdef MOZ_XUL
@@ -691,20 +688,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControllers, nsIControllers)
     DOM_CLASSINFO_MAP_ENTRY(nsIControllers)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(BoxObject, nsIBoxObject)
-    DOM_CLASSINFO_MAP_ENTRY(nsIBoxObject)
-  DOM_CLASSINFO_MAP_END
-
 #ifdef MOZ_XUL
   DOM_CLASSINFO_MAP_BEGIN(TreeSelection, nsITreeSelection)
     DOM_CLASSINFO_MAP_ENTRY(nsITreeSelection)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(TreeContentView, nsITreeContentView)
     DOM_CLASSINFO_MAP_ENTRY(nsITreeContentView)
     DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
@@ -1387,41 +1380,28 @@ nsDOMClassInfo::ShutDown()
 
   sConstructor_id     = JSID_VOID;
   sWrappedJSObject_id = JSID_VOID;
 
   NS_IF_RELEASE(sXPConnect);
   sIsInitialized = false;
 }
 
-static nsDOMConstructorFunc
-FindConstructorFunc(const nsDOMClassInfoData *aDOMClassInfoData)
-{
-  return nullptr;
-}
-
 static nsresult
 BaseStubConstructor(nsIWeakReference* aWeakOwner,
                     const nsGlobalNameStruct *name_struct, JSContext *cx,
                     JS::Handle<JSObject*> obj, const JS::CallArgs &args)
 {
   MOZ_ASSERT(obj);
   MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
 
   nsresult rv;
   nsCOMPtr<nsISupports> native;
   if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
-    const nsDOMClassInfoData* ci_data =
-      &sClassInfoData[name_struct->mDOMClassInfoID];
-    nsDOMConstructorFunc func = FindConstructorFunc(ci_data);
-    if (func) {
-      rv = func(getter_AddRefs(native));
-    } else {
-      rv = NS_ERROR_NOT_AVAILABLE;
-    }
+    rv = NS_ERROR_NOT_AVAILABLE;
   } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
     native = do_CreateInstance(name_struct->mCID, &rv);
   } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
     native = do_CreateInstance(name_struct->mAlias->mCID, &rv);
   } else {
     native = do_CreateInstance(*name_struct->mData->mConstructorCID, &rv);
   }
   if (NS_FAILED(rv)) {
@@ -1621,17 +1601,17 @@ private:
   static bool IsConstructable(const nsDOMClassInfoData *aData)
   {
     if (IS_EXTERNAL(aData->mCachedClassInfo)) {
       const nsExternalDOMClassInfoData* data =
         static_cast<const nsExternalDOMClassInfoData*>(aData);
       return data->mConstructorCID != nullptr;
     }
 
-    return FindConstructorFunc(aData);
+    return nullptr;
   }
   static bool IsConstructable(const nsGlobalNameStruct *aNameStruct)
   {
     return
       (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
        IsConstructable(&sClassInfoData[aNameStruct->mDOMClassInfoID])) ||
       (aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo &&
        IsConstructable(aNameStruct->mData)) ||
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -14,17 +14,16 @@ DOMCI_CLASS(CSSImportRule)
 DOMCI_CLASS(CSSMediaRule)
 DOMCI_CLASS(CSSNameSpaceRule)
 
 // XUL classes
 #ifdef MOZ_XUL
 DOMCI_CLASS(XULCommandDispatcher)
 #endif
 DOMCI_CLASS(XULControllers)
-DOMCI_CLASS(BoxObject)
 #ifdef MOZ_XUL
 DOMCI_CLASS(TreeSelection)
 DOMCI_CLASS(TreeContentView)
 #endif
 
 #ifdef MOZ_XUL
 DOMCI_CLASS(XULTemplateBuilder)
 DOMCI_CLASS(XULTreeBuilder)
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -170,16 +170,20 @@ DOMInterfaces = {
     'nativeType': 'mozilla::dom::bluetooth::BluetoothPairingHandle',
 },
 
 'BluetoothPairingListener': {
     'nativeType':
       'mozilla::dom::bluetooth::BluetoothPairingListener',
 },
 
+'BoxObject': {
+    'resultNotAddRefed': ['element'],
+},
+
 'CameraCapabilities': {
     'nativeType': 'mozilla::dom::CameraCapabilities',
     'headerFile': 'DOMCameraCapabilities.h'
 },
 
 'CameraControl': {
     'nativeType': 'mozilla::nsDOMCameraControl',
     'headerFile': 'DOMCameraControl.h',
@@ -861,16 +865,20 @@ DOMInterfaces = {
     'headerFile' : 'nsPluginArray.h',
     'nativeType': 'nsPluginElement',
 },
 
 'PluginArray': {
     'nativeType': 'nsPluginArray',
 },
 
+'PopupBoxObject': {
+    'resultNotAddRefed': ['triggerNode', 'anchorNode'],
+},
+
 'Position': {
     'headerFile': 'nsGeoPosition.h'
 },
 
 'PositionError': {
     'headerFile': 'nsGeolocation.h'
 },
 
@@ -1797,31 +1805,30 @@ def addExternalIface(iface, nativeType=N
 addExternalIface('ApplicationCache', nativeType='nsIDOMOfflineResourceList')
 addExternalIface('Counter')
 addExternalIface('CSSRule')
 addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
-addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback',
                  notflattened=True)
 addExternalIface('MozMmsMessage')
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozSmsMessage')
-addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
-                 notflattened=True)
 addExternalIface('MozTreeColumn', nativeType='nsITreeColumn',
                  headerFile='nsITreeColumns.h')
+addExternalIface('MozTreeView', nativeType='nsITreeView',
+                  headerFile='nsITreeView.h')
 addExternalIface('MozWakeLockListener', headerFile='nsIDOMWakeLockListener.h')
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow',
                  notflattened=True)
 addExternalIface('nsIControllers', nativeType='nsIControllers')
 addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
                  headerFile='Crypto.h')
 addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
@@ -1830,16 +1837,17 @@ addExternalIface('nsIFile', nativeType='
 addExternalIface('nsIMessageBroadcaster', nativeType='nsIMessageBroadcaster',
                  headerFile='nsIMessageManager.h', notflattened=True)
 addExternalIface('nsISelectionListener', nativeType='nsISelectionListener')
 addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True)
 addExternalIface('nsISupports', nativeType='nsISupports')
 addExternalIface('nsIDocShell', nativeType='nsIDocShell', notflattened=True)
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
+addExternalIface('nsIScriptableRegion', nativeType='nsIScriptableRegion', notflattened=True)
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('StackFrame', nativeType='nsIStackFrame',
                  headerFile='nsIException.h', notflattened=True)
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
--- a/dom/bluetooth2/BluetoothAdapter.cpp
+++ b/dom/bluetooth2/BluetoothAdapter.cpp
@@ -9,16 +9,17 @@
 #include "BluetoothUtils.h"
 #include "DOMRequest.h"
 #include "nsTArrayHelpers.h"
 
 #include "mozilla/dom/BluetoothAdapter2Binding.h"
 #include "mozilla/dom/BluetoothAttributeEvent.h"
 #include "mozilla/dom/BluetoothStatusChangedEvent.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/File.h"
 
 #include "mozilla/dom/bluetooth/BluetoothAdapter.h"
 #include "mozilla/dom/bluetooth/BluetoothClassOfDevice.h"
 #include "mozilla/dom/bluetooth/BluetoothDevice.h"
 #include "mozilla/dom/bluetooth/BluetoothDiscoveryHandle.h"
 #include "mozilla/dom/bluetooth/BluetoothPairingListener.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
@@ -1020,17 +1021,17 @@ BluetoothAdapter::Disconnect(BluetoothDe
   }
   bs->Disconnect(address, serviceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
-                           nsIDOMBlob* aBlob, ErrorResult& aRv)
+                           File& aBlob, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
@@ -1040,25 +1041,25 @@ BluetoothAdapter::SendFile(const nsAStri
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     // In-process transfer
-    bs->SendFile(aDeviceAddress, aBlob, results);
+    bs->SendFile(aDeviceAddress, &aBlob, results);
   } else {
     ContentChild *cc = ContentChild::GetSingleton();
     if (!cc) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
-    BlobChild* actor = cc->GetOrCreateActorForBlob(aBlob);
+    BlobChild* actor = cc->GetOrCreateActorForBlob(&aBlob);
     if (!actor) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     bs->SendFile(aDeviceAddress, nullptr, actor, results);
   }
 
--- a/dom/bluetooth2/BluetoothAdapter.h
+++ b/dom/bluetooth2/BluetoothAdapter.h
@@ -13,16 +13,17 @@
 #include "mozilla/dom/BluetoothAdapter2Binding.h"
 #include "mozilla/dom/BluetoothDeviceEvent.h"
 #include "mozilla/dom/Promise.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
 class DOMRequest;
+class File;
 struct MediaMetaData;
 struct MediaPlayStatus;
 }
 }
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothDevice;
@@ -119,17 +120,17 @@ public:
     Disconnect(BluetoothDevice& aDevice,
                const Optional<short unsigned int>& aServiceUuid,
                ErrorResult& aRv);
   already_AddRefed<DOMRequest> GetConnectedDevices(uint16_t aServiceUuid,
                                                    ErrorResult& aRv);
 
   // OPP file transfer related methods
   already_AddRefed<DOMRequest> SendFile(const nsAString& aDeviceAddress,
-                                        nsIDOMBlob* aBlob,
+                                        File& aBlob,
                                         ErrorResult& aRv);
   already_AddRefed<DOMRequest> StopSendingFile(const nsAString& aDeviceAddress,
                                                ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     ConfirmReceivingFile(const nsAString& aDeviceAddress,
                          bool aConfirmation,
                          ErrorResult& aRv);
 
--- a/dom/bluetooth2/bluedroid/BluetoothOppManager.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothOppManager.cpp
@@ -10,36 +10,37 @@
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIDOMFile.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIOutputStream.h"
 #include "nsIVolumeService.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
 #define TARGET_SUBDIR "Download/Bluetooth/"
 
 USING_BLUETOOTH_NAMESPACE
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 namespace {
 // Sending system message "bluetooth-opp-update-progress" every 50kb
 static const uint32_t kUpdateProgressBase = 50 * 1024;
 
 /*
  * The format of the header of an PUT request is
@@ -344,17 +345,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+  nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
+  nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
@@ -820,17 +820,17 @@ public:
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     sBondingRunnableArray.RemoveElement(mRunnable);
     ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("CreatedPairedDevice"));
   }
 
 private:
-  BluetoothReplyRunnable* mRunnable;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
 };
 
 nsresult
 BluetoothServiceBluedroid::CreatePairedDeviceInternal(
   const nsAString& aDeviceAddress, int aTimeout,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -855,17 +855,17 @@ public:
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     sUnbondingRunnableArray.RemoveElement(mRunnable);
     ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("RemoveDevice"));
   }
 
 private:
-  BluetoothReplyRunnable* mRunnable;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
 };
 
 nsresult
 BluetoothServiceBluedroid::RemoveDeviceInternal(
   const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
@@ -363,24 +363,37 @@ public:
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (mImpl->IsShutdownOnMainThread()) {
       BT_LOGD("mConsumer is null, aborting receive!");
       return;
     }
 
+    if (aConnectionStatus != 0) {
+      mImpl->mConsumer->NotifyError();
+      return;
+    }
+
     mImpl->mConsumer->SetAddress(aBdAddress);
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new AcceptTask(mImpl, aFd));
   }
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     BT_LOGR("BluetoothSocketInterface::Accept failed: %d", (int)aStatus);
+
+    if (!mImpl->IsShutdownOnMainThread()) {
+      // Instead of NotifyError(), call NotifyDisconnect() to trigger
+      // BluetoothOppManager::OnSocketDisconnect() as
+      // DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
+      // order to keep the same behavior and reduce regression risk.
+      mImpl->mConsumer->NotifyDisconnect();
+    }
   }
 
 private:
   DroidSocketImpl* mImpl;
 };
 
 class AcceptRunnable MOZ_FINAL : public SocketIORunnable<DroidSocketImpl>
 {
@@ -499,27 +512,43 @@ public:
     MOZ_ASSERT(mImpl);
   }
 
   void Connect(int aFd, const nsAString& aBdAddress,
                int aConnectionStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    if (!mImpl->IsShutdownOnMainThread()) {
-      mImpl->mConsumer->SetAddress(aBdAddress);
+    if (mImpl->IsShutdownOnMainThread()) {
+      BT_LOGD("mConsumer is null, aborting send!");
+      return;
     }
+
+    if (aConnectionStatus != 0) {
+      mImpl->mConsumer->NotifyError();
+      return;
+    }
+
+    mImpl->mConsumer->SetAddress(aBdAddress);
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
                                      new SocketConnectTask(mImpl, aFd));
   }
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     BT_WARNING("Connect failed: %d", (int)aStatus);
+
+    if (!mImpl->IsShutdownOnMainThread()) {
+      // Instead of NotifyError(), call NotifyDisconnect() to trigger
+      // BluetoothOppManager::OnSocketDisconnect() as
+      // DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
+      // order to keep the same behavior and reduce regression risk.
+      mImpl->mConsumer->NotifyDisconnect();
+    }
   }
 
 private:
   DroidSocketImpl* mImpl;
 };
 
 bool
 BluetoothSocket::ConnectSocket(const nsAString& aDeviceAddress, int aChannel)
--- a/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
@@ -281,17 +281,17 @@ private:
     iv.iov_len = MSG1_SIZE;
 
     struct msghdr msg;
     memset(&msg, 0, sizeof(msg));
     msg.msg_iov = &iv;
     msg.msg_iovlen = 1;
 
     ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
-    if (res < 0) {
+    if (res <= 0) {
       return STATUS_FAIL;
     }
 
     mLen += res;
 
     return STATUS_SUCCESS;
   }
 
@@ -306,17 +306,17 @@ private:
     struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100];
     memset(&msg, 0, sizeof(msg));
     msg.msg_iov = &iv;
     msg.msg_iovlen = 1;
     msg.msg_control = cmsgbuf;
     msg.msg_controllen = sizeof(cmsgbuf);
 
     ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
-    if (res < 0) {
+    if (res <= 0) {
       return STATUS_FAIL;
     }
 
     mLen += res;
 
     if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) {
       return STATUS_FAIL;
     }
--- a/dom/bluetooth2/bluez/BluetoothOppManager.cpp
+++ b/dom/bluetooth2/bluez/BluetoothOppManager.cpp
@@ -10,36 +10,37 @@
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIDOMFile.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIOutputStream.h"
 #include "nsIVolumeService.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 
 #define TARGET_SUBDIR "Download/Bluetooth/"
 
 USING_BLUETOOTH_NAMESPACE
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 
 namespace {
 // Sending system message "bluetooth-opp-update-progress" every 50kb
 static const uint32_t kUpdateProgressBase = 50 * 1024;
 
@@ -366,17 +367,18 @@ BluetoothOppManager::StartSendingNextFil
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               BlobParent* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIDOMBlob> blob = aActor->GetBlob();
+  nsRefPtr<FileImpl> impl = aActor->GetBlobImpl();
+  nsCOMPtr<nsIDOMBlob> blob = new File(nullptr, impl);
 
   return SendFile(aDeviceAddress, blob.get());
 }
 
 bool
 BluetoothOppManager::SendFile(const nsAString& aDeviceAddress,
                               nsIDOMBlob* aBlob)
 {
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3199,17 +3199,17 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
         // in the font, and adjust accordingly.
         // (The same will be true for HTML text layout.)
         const gfxFont::Metrics& metrics = mTextRun->GetFontGroup()->
           GetFirstValidFont()->GetMetrics(gfxFont::eHorizontal);
         mCtx->mTarget->SetTransform(mCtx->mTarget->GetTransform().Copy().
           PreTranslate(baselineOrigin).      // translate origin for rotation
           PreRotate(gfx::Float(M_PI / 2.0)). // turn 90deg clockwise
           PreTranslate(-baselineOrigin).     // undo the translation
-          PreTranslate(Point(0, metrics.emAscent - metrics.emDescent) / 2));
+          PreTranslate(Point(0, (metrics.emAscent - metrics.emDescent) / 2)));
                               // and offset the (alphabetic) baseline of the
                               // horizontally-shaped text from the (centered)
                               // default baseline used for vertical
       }
 
       RefPtr<GlyphRenderingOptions> renderingOptions = font->GetGlyphRenderingOptions();
 
       GlyphBuffer buffer;
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -73,17 +73,18 @@ WebGLContext::InitWebGL2()
         WebGLExtensionID::OES_texture_half_float,
         WebGLExtensionID::OES_texture_half_float_linear,
         WebGLExtensionID::OES_vertex_array_object,
         WebGLExtensionID::WEBGL_depth_texture,
         WebGLExtensionID::WEBGL_draw_buffers
     };
     const GLFeature sFeatureRequiredArr[] = {
         GLFeature::instanced_non_arrays,
-        GLFeature::transform_feedback2
+        GLFeature::transform_feedback2,
+        GLFeature::invalidate_framebuffer
     };
 
     // check WebGL extensions that are supposed to be natively supported
     for (size_t i = 0; i < size_t(MOZ_ARRAY_LENGTH(sExtensionNativelySupportedArr)); i++)
     {
         WebGLExtensionID extension = sExtensionNativelySupportedArr[i];
 
         if (!IsExtensionSupported(extension)) {
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -243,13 +243,14 @@ public:
 private:
 
     WebGL2Context();
 
     bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
     bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
                                 GLsizei width, GLsizei height, GLsizei depth,
                                 const char* info);
+    JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -27,27 +27,83 @@ WebGL2Context::FramebufferTextureLayer(G
 }
 
 void
 WebGL2Context::GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval)
 {
     MOZ_CRASH("Not Implemented.");
 }
 
+// Map attachments intended for the default buffer, to attachments for a non-
+// default buffer.
+static void
+TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
+{
+    for (size_t i = 0; i < in.Length(); i++) {
+        switch (in[i]) {
+            case LOCAL_GL_COLOR:
+                out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0);
+                break;
+            case LOCAL_GL_DEPTH:
+                out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT);
+                break;
+            case LOCAL_GL_STENCIL:
+                out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT);
+                break;
+        }
+    }
+}
+
 void
 WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+    MakeContextCurrent();
+
+    if (target != LOCAL_GL_FRAMEBUFFER)
+        return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
+    for (size_t i = 0; i < attachments.Length(); i++) {
+        if (!ValidateFramebufferAttachment(attachments[i], "invalidateFramebuffer"))
+            return;
+    }
+
+    if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
+        dom::Sequence<GLenum> tmpAttachments;
+        TranslateDefaultAttachments(attachments, &tmpAttachments);
+        gl->fInvalidateFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements());
+    } else {
+        gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
+    }
 }
 
 void
-WebGL2Context::InvalidateSubFramebuffer (GLenum target, const dom::Sequence<GLenum>& attachments,
-                                         GLint x, GLint y, GLsizei width, GLsizei height)
+WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
+                                        GLint x, GLint y, GLsizei width, GLsizei height)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+    MakeContextCurrent();
+
+    if (target != LOCAL_GL_FRAMEBUFFER)
+        return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
+    for (size_t i = 0; i < attachments.Length(); i++) {
+        if (!ValidateFramebufferAttachment(attachments[i], "invalidateSubFramebuffer"))
+            return;
+    }
+
+    if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
+        dom::Sequence<GLenum> tmpAttachments;
+        TranslateDefaultAttachments(attachments, &tmpAttachments);
+        gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements(),
+                                      x, y, width, height);
+    } else {
+        gl->fInvalidateSubFramebuffer(target, attachments.Length(), attachments.Elements(),
+                                      x, y, width, height);
+    }
 }
 
 void
 WebGL2Context::ReadBuffer(GLenum mode)
 {
     MOZ_CRASH("Not Implemented.");
 }
 
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -287,17 +287,17 @@ WebGL2Context::TexSubImage3D(GLenum rawT
                                 yoffset == 0 &&
                                 zoffset == 0 &&
                                 width == imageInfo.Width() &&
                                 height == imageInfo.Height() &&
                                 depth == imageInfo.Depth();
         if (coversWholeImage) {
             tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
         } else {
-            tex->DoDeferredImageInitialization(texImageTarget, level);
+            tex->EnsureNoUninitializedImageData(texImageTarget, level);
         }
     }
 
     GLenum driverType = LOCAL_GL_NONE;
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
     DriverFormatsFromEffectiveInternalFormat(gl,
                                              existingEffectiveInternalFormat,
@@ -340,8 +340,22 @@ WebGL2Context::CompressedTexImage3D(GLen
 
 void
 WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                        GLsizei width, GLsizei height, GLsizei depth,
                                        GLenum format, GLsizei imageSize, const dom::ArrayBufferView& data)
 {
     MOZ_CRASH("Not Implemented.");
 }
+
+JS::Value
+WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname)
+{
+    switch (pname) {
+        case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
+        {
+            GLint i = 0;
+            gl->fGetTexParameteriv(target.get(), pname, &i);
+            return JS::NumberValue(uint32_t(i));
+        }
+    }
+    return WebGLContext::GetTexParameterInternal(target, pname);
+}
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -985,16 +985,18 @@ protected:
     void UndoFakeVertexAttrib0();
 
     static CheckedUint32 GetImageSize(GLsizei height,
                                       GLsizei width,
                                       GLsizei depth,
                                       uint32_t pixelSize,
                                       uint32_t alignment);
 
+    virtual JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname);
+
     // Returns x rounded to the next highest multiple of y.
     static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
         return ((x + y - 1) / y) * y;
     }
 
     nsRefPtr<gl::GLContext> gl;
 
     CheckedUint32 mGeneration;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -448,17 +448,17 @@ WebGLContext::CopyTexSubImage2D_base(Tex
 
         // the rect doesn't fit in the framebuffer
 
         // first, we initialize the texture as black
         if (!sub) {
             tex->SetImageInfo(texImageTarget, level, width, height, 1,
                       effectiveInternalFormat,
                       WebGLImageDataStatus::UninitializedImageData);
-            tex->DoDeferredImageInitialization(texImageTarget, level);
+            tex->EnsureNoUninitializedImageData(texImageTarget, level);
         }
 
         // if we are completely outside of the framebuffer, we can exit now with our black texture
         if (   x >= framebufferWidth
             || x+width <= 0
             || y >= framebufferHeight
             || y+height <= 0)
         {
@@ -596,17 +596,17 @@ WebGLContext::CopyTexSubImage2D(GLenum r
     if (imageInfo.HasUninitializedImageData()) {
         bool coversWholeImage = xoffset == 0 &&
                                 yoffset == 0 &&
                                 width == texWidth &&
                                 height == texHeight;
         if (coversWholeImage) {
             tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
         } else {
-            tex->DoDeferredImageInitialization(texImageTarget, level);
+            tex->EnsureNoUninitializedImageData(texImageTarget, level);
         }
     }
 
     TexInternalFormat internalformat;
     TexType type;
     UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(imageInfo.EffectiveInternalFormat(),
                                              &internalformat, &type);
     return CopyTexSubImage2D_base(texImageTarget, level, internalformat, xoffset, yoffset, x, y, width, height, true);
@@ -922,17 +922,17 @@ WebGLContext::GenerateMipmap(GLenum rawT
     const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D)
                                                   ? LOCAL_GL_TEXTURE_2D
                                                   : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     if (!tex->HasImageInfoAt(imageTarget, 0))
     {
         return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
     }
 
-    if (!tex->IsFirstImagePowerOfTwo())
+    if (!IsWebGL2() && !tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
     TexInternalFormat internalformat = tex->ImageInfoAt(imageTarget, 0).EffectiveInternalFormat();
     if (IsTextureFormatCompressed(internalformat))
         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
 
     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
         (IsGLDepthFormat(internalformat) || IsGLDepthStencilFormat(internalformat)))
@@ -1606,16 +1606,22 @@ WebGLContext::GetTexParameter(GLenum raw
 
     const TexTarget target(rawTarget);
 
     if (!activeBoundTextureForTarget(target)) {
         ErrorInvalidOperation("getTexParameter: no texture bound");
         return JS::NullValue();
     }
 
+    return GetTexParameterInternal(target, pname);
+}
+
+JS::Value
+WebGLContext::GetTexParameterInternal(const TexTarget& target, GLenum pname)
+{
     switch (pname) {
         case LOCAL_GL_TEXTURE_MIN_FILTER:
         case LOCAL_GL_TEXTURE_MAG_FILTER:
         case LOCAL_GL_TEXTURE_WRAP_S:
         case LOCAL_GL_TEXTURE_WRAP_T:
         {
             GLint i = 0;
             gl->fGetTexParameteriv(target.get(), pname, &i);
@@ -3425,17 +3431,17 @@ WebGLContext::CompressedTexSubImage2D(GL
     if (levelInfo.HasUninitializedImageData()) {
         bool coversWholeImage = xoffset == 0 &&
                                 yoffset == 0 &&
                                 width == levelInfo.Width() &&
                                 height == levelInfo.Height();
         if (coversWholeImage) {
             tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
         } else {
-            tex->DoDeferredImageInitialization(texImageTarget, level);
+            tex->EnsureNoUninitializedImageData(texImageTarget, level);
         }
     }
 
     MakeContextCurrent();
     gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, internalformat, byteLength, view.Data());
 }
 
 JS::Value
@@ -3961,17 +3967,17 @@ WebGLContext::TexSubImage2D_base(TexImag
     if (imageInfo.HasUninitializedImageData()) {
         bool coversWholeImage = xoffset == 0 &&
                                 yoffset == 0 &&
                                 width == imageInfo.Width() &&
                                 height == imageInfo.Height();
         if (coversWholeImage) {
             tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
         } else {
-            tex->DoDeferredImageInitialization(texImageTarget, level);
+            tex->EnsureNoUninitializedImageData(texImageTarget, level);
         }
     }
     MakeContextCurrent();
 
     size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
     uint32_t dstTexelSize = GetBitsPerTexel(existingEffectiveInternalFormat) / 8;
     size_t   dstPlainRowSize = dstTexelSize * width;
     // There are checks above to ensure that this won't overflow.
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -172,16 +172,28 @@ WebGLContext::GetParameter(JSContext* cx
             if (mBoundVertexArray == mDefaultVertexArray){
                 return WebGLObjectAsJSValue(cx, (WebGLVertexArray *) nullptr, rv);
             }
 
             return WebGLObjectAsJSValue(cx, mBoundVertexArray.get(), rv);
         }
     }
 
+    if (IsWebGL2()) {
+        switch (pname) {
+            case LOCAL_GL_MAX_SAMPLES:
+            case LOCAL_GL_MAX_UNIFORM_BLOCK_SIZE:
+            case LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS: {
+                GLint val;
+                gl->fGetIntegerv(pname, &val);
+                return JS::NumberValue(uint32_t(val));
+            }
+        }
+    }
+
     switch (pname) {
         //
         // String params
         //
         case LOCAL_GL_VENDOR:
             return StringValue(cx, "Mozilla", rv);
         case LOCAL_GL_RENDERER:
             return StringValue(cx, "Mozilla", rv);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -334,16 +334,28 @@ bool WebGLContext::ValidateGLSLString(co
 
 /**
  * Return true if the framebuffer attachment is valid. Attachment must
  * be one of depth/stencil/depth_stencil/color attachment.
  */
 bool
 WebGLContext::ValidateFramebufferAttachment(GLenum attachment, const char* funcName)
 {
+    if (!mBoundFramebuffer) {
+        switch (attachment) {
+            case LOCAL_GL_COLOR:
+            case LOCAL_GL_DEPTH:
+            case LOCAL_GL_STENCIL:
+                return true;
+            default:
+                ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName, attachment);
+                return false;
+        }
+    }
+
     if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
         attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
         attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
     {
         return true;
     }
 
     GLenum colorAttachCount = 1;
@@ -799,18 +811,20 @@ WebGLContext::ValidateTexImageSize(TexIm
                               InfoFrom(func, dims), level, maxTexImageSize);
             return false;
         }
 
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "If level is greater than zero, and either width or
          *   height is not a power-of-two, the error INVALID_VALUE is
          *   generated."
+         *
+         * This restriction does not apply to GL ES Version 3.0+.
          */
-        if (level > 0) {
+        if (!IsWebGL2() && level > 0) {
             if (!is_pot_assuming_nonnegative(width)) {
                 ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
                                   InfoFrom(func, dims), width);
                 return false;
             }
 
             if (!is_pot_assuming_nonnegative(height)) {
                 ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
@@ -822,17 +836,17 @@ WebGLContext::ValidateTexImageSize(TexIm
 
     // TODO: WebGL 2
     if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
         if (depth < 0) {
             ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func, dims));
             return false;
         }
 
-        if (depth > 0 && !is_pot_assuming_nonnegative(depth)) {
+        if (!IsWebGL2() && !is_pot_assuming_nonnegative(depth)) {
             ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
                               InfoFrom(func, dims), depth);
             return false;
         }
     }
 
     return true;
 }
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -181,29 +181,29 @@ void
 WebGLTexture::SetCustomMipmap() {
     if (mHaveGeneratedMipmap) {
         // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
         // we need to compute now all the mipmap image info.
 
         // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
         // and are power-of-two.
         ImageInfo imageInfo = ImageInfoAtFace(0, 0);
-        NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
+        NS_ASSERTION(mContext->IsWebGL2() || imageInfo.IsPowerOfTwo(),
+                     "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
 
         GLsizei size = std::max(std::max(imageInfo.mWidth, imageInfo.mHeight), imageInfo.mDepth);
 
-        // so, the size is a power of two, let's find its log in base 2.
+        // Find floor(log2(size)). (ES 3.0.4, 3.8 - Mipmapping).
         size_t maxLevel = 0;
         for (GLsizei n = size; n > 1; n >>= 1)
             ++maxLevel;
 
         EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
 
         for (size_t level = 1; level <= maxLevel; ++level) {
-            // again, since the sizes are powers of two, no need for any max(1,x) computation
             imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
             imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
             imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
             for(size_t face = 0; face < mFacesCount; ++face)
                 ImageInfoAtFace(face, level) = imageInfo;
         }
     }
     mHaveGeneratedMipmap = false;
@@ -280,67 +280,69 @@ WebGLTexture::ResolvedFakeBlackStatus() 
         int dim = mTarget == LOCAL_GL_TEXTURE_2D ? 2 : 3;
         if (DoesMinFilterRequireMipmap())
         {
             if (!IsMipmapComplete()) {
                 mContext->GenerateWarning
                     ("%s is a %dD texture, with a minification filter requiring a mipmap, "
                       "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black, dim);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
-            } else if (!ImageInfoBase().IsPowerOfTwo()) {
+            } else if (!mContext->IsWebGL2() && !ImageInfoBase().IsPowerOfTwo()) {
                 mContext->GenerateWarning
                     ("%s is a %dD texture, with a minification filter requiring a mipmap, "
                       "and either its width or height is not a power of two.", msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
         else // no mipmap required
         {
             if (!ImageInfoBase().IsPositive()) {
                 mContext->GenerateWarning
                     ("%s is a %dD texture and its width or height is equal to zero.",
                       msg_rendering_as_black, dim);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
-            } else if (!AreBothWrapModesClampToEdge() && !ImageInfoBase().IsPowerOfTwo()) {
+            } else if (!AreBothWrapModesClampToEdge() && !mContext->IsWebGL2() && !ImageInfoBase().IsPowerOfTwo()) {
                 mContext->GenerateWarning
                     ("%s is a %dD texture, with a minification filter not requiring a mipmap, "
                       "with its width or height not a power of two, and with a wrap mode "
                       "different from CLAMP_TO_EDGE.", msg_rendering_as_black, dim);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
     }
     else // cube map
     {
-        bool areAllLevel0ImagesPOT = true;
-        for (size_t face = 0; face < mFacesCount; ++face)
-            areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
+        bool legalImageSize = true;
+        if (!mContext->IsWebGL2()) {
+            for (size_t face = 0; face < mFacesCount; ++face)
+                legalImageSize &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
+        }
 
         if (DoesMinFilterRequireMipmap())
         {
             if (!IsMipmapCubeComplete()) {
                 mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
                             "and is not mipmap cube complete (as defined in section 3.7.10).",
                             msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
-            } else if (!areAllLevel0ImagesPOT) {
+            } else if (!legalImageSize) {
                 mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
                             "and either the width or the height of some level 0 image is not a power of two.",
                             msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
         else // no mipmap required
         {
             if (!IsCubeComplete()) {
                 mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
                             "and is not cube complete (as defined in section 3.7.10).",
                             msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
-            } else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
+            } else if (!AreBothWrapModesClampToEdge() && !legalImageSize) {
                 mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
                             "with some level 0 image having width or height not a power of two, and with a wrap mode "
                             "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
     }
 
@@ -417,17 +419,17 @@ WebGLTexture::ResolvedFakeBlackStatus() 
             // in this case we know that we can't be dealing with a depth texture per WEBGL_depth_texture
             // and ANGLE_depth_texture (which allow only one image per texture) so we can assume that
             // glTexImage2D is able to upload data to images.
             for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
                 for (size_t face = 0; face < mFacesCount; ++face) {
                     TexImageTarget imageTarget = TexImageTargetForTargetAndFace(mTarget, face);
                     const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
                     if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData) {
-                        DoDeferredImageInitialization(imageTarget, level);
+                        EnsureNoUninitializedImageData(imageTarget, level);
                     }
                 }
             }
             mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
         } else {
             // The texture only contains uninitialized image data. In this case,
             // we can use a black texture for it.
             mFakeBlackStatus = WebGLTextureFakeBlackStatus::UninitializedImageData;
@@ -537,20 +539,21 @@ ClearWithTempFB(WebGLContext* context, G
     mask |= LOCAL_GL_COLOR_BUFFER_BIT;
 
     // Last chance!
     return ClearByMask(context, mask);
 }
 
 
 void
-WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level)
+WebGLTexture::EnsureNoUninitializedImageData(TexImageTarget imageTarget, GLint level)
 {
     const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
-    MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
+    if (!imageInfo.HasUninitializedImageData())
+        return;
 
     mContext->MakeContextCurrent();
 
     // Try to clear with glCLear.
 
     if (imageTarget == LOCAL_GL_TEXTURE_2D) {
         bool cleared = ClearWithTempFB(mContext, GLName(),
                                        imageTarget, level,
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -194,17 +194,17 @@ public:
         MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
                    imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
         if (imageInfo.mImageDataStatus != newStatus) {
             SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
         }
         imageInfo.mImageDataStatus = newStatus;
     }
 
-    void DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level);
+    void EnsureNoUninitializedImageData(TexImageTarget imageTarget, GLint level);
 
 protected:
 
     TexMinFilter mMinFilter;
     TexMagFilter mMagFilter;
     TexWrap mWrapS, mWrapT;
 
     size_t mFacesCount, mMaxLevelWithCustomImages;
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -19,8 +19,10 @@ skip-if = toolkit == 'android' #bug 8654
 [webgl-mochitest/test_webgl_conformance.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_request_context.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_request_mismatch.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl2_not_exposed.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
+[webgl-mochitest/test_webgl2_invalidate_framebuffer.html]
+skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_webgl2_invalidate_framebuffer.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+<title>WebGL2 test: Framebuffers</title>
+
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="driver-info.js"></script>
+<script src="webgl-util.js"></script>
+<body>
+<canvas id="c" width="64" height="64"></canvas>
+<script>
+
+WebGLUtil.withWebGL2('c', function (gl) {
+  gl.invalidateFramebuffer(gl.FRAMEBUFFER, [gl.COLOR]);
+  ok(gl.getError() == 0, 'invalidateFramebuffer');
+  gl.invalidateSubFramebuffer(gl.FRAMEBUFFER, [gl.COLOR], 0, 0, 64, 64);
+  ok(gl.getError() == 0, 'invalidateSubFramebuffer');
+  gl.invalidateFramebuffer(gl.FRAMEBUFFER, [gl.GL_COLOR_ATTACHMENT0]);
+  ok(gl.getError() == gl.INVALID_ENUM, 'invalidateFrameBuffer should fail with GL_COLOR_ATTACHMENT on the default framebuffer');
+}, function () {
+  SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
--- a/dom/canvas/test/webgl-mochitest/webgl-util.js
+++ b/dom/canvas/test/webgl-mochitest/webgl-util.js
@@ -53,16 +53,54 @@ WebGLUtil = (function() {
     if (!gl) {
       error('WebGL context could not be retrieved from \'' + canvasId + '\'.');
       return null;
     }
 
     return gl;
   }
 
+  function withWebGL2(canvasId, callback, onFinished) {
+    var prefArrArr = [
+      ['webgl.force-enabled', true],
+      ['webgl.disable-angle', true],
+      ['webgl.enable-prototype-webgl2', true],
+    ];
+    var prefEnv = {'set': prefArrArr};
+    SpecialPowers.pushPrefEnv(prefEnv, function() {
+      var canvas = document.getElementById(canvasId);
+
+      var gl = null;
+      try {
+        gl = canvas.getContext('webgl2');
+      } catch(e) {}
+
+      if (!gl) {
+        try {
+          gl = canvas.getContext('experimental-webgl2');
+        } catch(e) {}
+      }
+
+      if (!gl) {
+        todo(false, 'WebGL2 is not supported');
+        onFinished();
+        return;
+      }
+
+      function errorFunc(str) {
+        ok(false, 'Error: ' + str);
+      }
+      setErrorFunc(errorFunc);
+      setWarningFunc(errorFunc);
+
+      callback(gl);
+      onFinished();
+    });
+  }
+
   function getContentFromElem(elem) {
     var str = "";
     var k = elem.firstChild;
     while (k) {
       if (k.nodeType == 3)
         str += k.textContent;
 
       k = k.nextSibling;
@@ -120,12 +158,13 @@ WebGLUtil = (function() {
     return prog;
   }
 
   return {
     setErrorFunc: setErrorFunc,
     setWarningFunc: setWarningFunc,
 
     getWebGL: getWebGL,
+    withWebGL2: withWebGL2,
     createShaderById: createShaderById,
     createProgramByIds: createProgramByIds,
   };
 })();
--- a/dom/events/test/test_bug602962.xul
+++ b/dom/events/test/test_bug602962.xul
@@ -25,36 +25,35 @@ var oldWidth = 0, oldHeight = 0;
 var win = null;
 
 function openWindow() {
   win = window.open("chrome://mochitests/content/chrome/dom/events/test/bug602962.xul", "_blank", "width=600,height=600");
 }
 
 function doTest() {
   scrollbox = win.document.getElementById("page-scrollbox");
-  sbo = scrollbox.boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject);
+  sbo = scrollbox.boxObject;
   content = win.document.getElementById("page-box");
   content.style.width = 400 + "px";
   
   win.addEventListener("resize", function() {
     win.removeEventListener("resize", arguments.callee, false);
 
     sbo.scrollBy(200, 0);
     setTimeout(function() { resize(); }, 0);
   }, false);
 
   oldWidth = win.outerWidth;
   oldHeight = win.outerHeight;
   win.resizeTo(200, 400);
 }
 
 function resize() {
-  let x = {}, y = {};
-  sbo.getPosition(x, y);
-  scrollX = x.value, scrollY = y.value;
+  scrollX = sbo.positionX;
+  scrollY = sbo.positionY;
 
   win.addEventListener("resize", function() {
     content.style.width = (oldWidth + 400) + "px";
     win.removeEventListener("resize", arguments.callee, true);
     
     setTimeout(function() {
       finish();
     }, 0);
@@ -67,20 +66,18 @@ function finish() {
   if (win.outerWidth != oldWidth ||
       win.outerHeight != oldHeight) {
     // We should eventually get back to the original size.
     setTimeout(finish, 0);
     return;
   }
   sbo.scrollBy(scrollX, scrollY);
 
-  let x = {}, y = {};
-  sbo.getPosition(x, y);
-  is(x.value, 200, "Scroll X should have been restored to the value before the resize");
-  is(y.value, 0, "Scroll Y should have been restored to the value before the resize");
+  is(sbo.positionX, 200, "Scroll X should have been restored to the value before the resize");
+  is(sbo.positionY, 0, "Scroll Y should have been restored to the value before the resize");
 
   is(win.outerWidth, oldWidth, "Width should be resized");
   is(win.outerHeight, oldHeight, "Height should be resized");
   win.close();
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3017,16 +3017,17 @@ TabChild::RecvUIResolutionChanged()
   nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
   presContext->UIResolutionChanged();
   return true;
 }
 
 TabChildGlobal::TabChildGlobal(TabChildBase* aTabChild)
 : mTabChild(aTabChild)
 {
+  SetIsNotDOMBinding();
 }
 
 TabChildGlobal::~TabChildGlobal()
 {
 }
 
 void
 TabChildGlobal::Init()
--- a/dom/locales/en-US/chrome/layout/css.properties
+++ b/dom/locales/en-US/chrome/layout/css.properties
@@ -101,16 +101,19 @@ PEExpectedInt=Expected an integer but fo
 PEColorBadRGBContents=Expected number or percentage in rgb() but found '%1$S'.
 PEColorComponentBadTerm=Expected '%2$S' but found '%1$S'.
 PEColorHueEOF=hue
 PEExpectedComma=Expected ',' but found '%1$S'.
 PEColorSaturationEOF=saturation
 PEColorLightnessEOF=lightness
 PEColorOpacityEOF=opacity in color value
 PEExpectedNumber=Expected a number but found '%1$S'.
+PEPositionEOF=<position>
+PEExpectedPosition=Expected <position> but found '%1$S'.
+PEExpectedRadius=Expected radius but found '%1$S'.
 PEExpectedCloseParen=Expected ')' but found '%1$S'.
 PEDeclEndEOF=';' or '}' to end declaration
 PEParseDeclarationNoColon=Expected ':' but found '%1$S'.
 PEParseDeclarationDeclExpected=Expected declaration but found '%1$S'.
 PEEndOfDeclEOF=end of declaration
 PEImportantEOF=important
 PEExpectedImportant=Expected 'important' but found '%1$S'.
 PEBadDeclEnd=Expected ';' to terminate declaration but found '%1$S'.
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -2434,17 +2434,17 @@ PeerConnectionWrapper.prototype = {
   },
 
   /**
    * Checks that we are getting the media streams we expect.
    *
    * @param {object} stats
    *        The stats to check from this PeerConnectionWrapper
    */
-  checkStats : function PCW_checkStats(stats) {
+  checkStats : function PCW_checkStats(stats, twoMachines) {
     function toNum(obj) {
       return obj? obj : 0;
     }
     function numTracks(streams) {
       var n = 0;
       streams.forEach(function(stream) {
           n += stream.getAudioTracks().length + stream.getVideoTracks().length;
         });
@@ -2456,17 +2456,23 @@ PeerConnectionWrapper.prototype = {
     // Use spec way of enumerating stats
     var counters = {};
     for (var key in stats) {
       if (stats.hasOwnProperty(key)) {
         var res = stats[key];
         // validate stats
         ok(res.id == key, "Coherent stats id");
         var nowish = Date.now() + 1000;        // TODO: clock drift observed
+        if (twoMachines) {
+          nowish += 10000; // let's be very relaxed about clock sync
+        }
         var minimum = this.whenCreated - 1000; // on Windows XP (Bug 979649)
+        if (twoMachines) {
+          minimum -= 10000; // let's be very relaxed about clock sync
+        }
         if (isWinXP) {
           todo(false, "Can't reliably test rtcp timestamps on WinXP (Bug 979649)");
         } else {
           ok(res.timestamp >= minimum,
              "Valid " + (res.isRemote? "rtcp" : "rtp") + " timestamp " +
                  res.timestamp + " >= " + minimum + " (" +
                  (res.timestamp - minimum) + " ms)");
           ok(res.timestamp <= nowish,
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -473,26 +473,26 @@ var commandsPeerConnection = [
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_CHECK_STATS',
     function (test) {
       test.pcLocal.getStats(null, function(stats) {
-        test.pcLocal.checkStats(stats);
+        test.pcLocal.checkStats(stats, test.steeplechase);
         test.next();
       });
     }
   ],
   [
     'PC_REMOTE_CHECK_STATS',
     function (test) {
       test.pcRemote.getStats(null, function(stats) {
-        test.pcRemote.checkStats(stats);
+        test.pcRemote.checkStats(stats, test.steeplechase);
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
     function (test) {
       var pc = test.pcLocal;
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -735,18 +735,18 @@ void NetworkUtils::postTetherInterfaceLi
                                            CommandCallback aCallback,
                                            NetworkResultOptions& aResult)
 {
   // Send the dummy command to continue the function chain.
   char command[MAX_COMMAND_SIZE];
   snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
 
   char buf[BUF_SIZE];
-  const char* reason = NS_ConvertUTF16toUTF8(aResult.mResultReason).get();
-  memcpy(buf, reason, strlen(reason));
+  NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
+  memcpy(buf, reason.get(), reason.Length() + 1);
   split(buf, INTERFACE_DELIMIT, GET_FIELD(mInterfaceList));
 
   doCommand(command, aChain, aCallback);
 }
 
 void NetworkUtils::setIpForwardingEnabled(CommandChain* aChain,
                                           CommandCallback aCallback,
                                           NetworkResultOptions& aResult)
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -668,16 +668,18 @@ var interfaceNamesInGlobalScope =
     "MediaStreamAudioSourceNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaStreamEvent", pref: "media.peerconnection.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaStreamTrackEvent", pref: "media.peerconnection.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MediaStreamTrack",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MenuBoxObject", xbl: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "MessageEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MessagePort",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MimeType",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MimeTypeArray",
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -858,16 +860,18 @@ var interfaceNamesInGlobalScope =
     "PluginArray",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PointerEvent", pref: "dom.w3c_pointer_events.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PopStateEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PopupBlockedEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "PopupBoxObject", xbl: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "ProcessingInstruction",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ProgressEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Promise",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PropertyNodeList",
 // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BoxObject.webidl
@@ -0,0 +1,33 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Func="IsChromeOrXBL"]
+interface BoxObject {
+  readonly attribute Element? element;
+
+  readonly attribute long x;
+  readonly attribute long y;
+  [Throws]
+  readonly attribute long screenX;
+  [Throws]
+  readonly attribute long screenY;
+  readonly attribute long width;
+  readonly attribute long height;
+
+  nsISupports? getPropertyAsSupports(DOMString propertyName);
+  void setPropertyAsSupports(DOMString propertyName, nsISupports value);
+  [Throws]
+  DOMString? getProperty(DOMString propertyName);
+  void setProperty(DOMString propertyName, DOMString propertyValue);
+  void removeProperty(DOMString propertyName);
+
+  // for stepping through content in the expanded dom with box-ordinal-group order
+  readonly attribute Element? parentBox;
+  readonly attribute Element? firstChild;
+  readonly attribute Element? lastChild;
+  readonly attribute Element? nextSibling;
+  readonly attribute Element? previousSibling;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ContainerBoxObject.webidl
@@ -0,0 +1,12 @@
+
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[NoInterfaceObject]
+interface ContainerBoxObject : BoxObject {
+    [ChromeOnly]
+    readonly attribute nsIDocShell? docShell;
+};
--- a/dom/webidl/LegacyQueryInterface.webidl
+++ b/dom/webidl/LegacyQueryInterface.webidl
@@ -15,16 +15,17 @@ interface LegacyQueryInterface {
   // Legacy QueryInterface, only exposed to chrome or XBL code on the
   // main thread.
   [Exposed=Window]
   nsISupports queryInterface(IID iid);
 };
 
 Attr implements LegacyQueryInterface;
 BarProp implements LegacyQueryInterface;
+BoxObject implements LegacyQueryInterface;
 CaretPosition implements LegacyQueryInterface;
 Comment implements LegacyQueryInterface;
 Crypto implements LegacyQueryInterface;
 CSSPrimitiveValue implements LegacyQueryInterface;
 CSSStyleDeclaration implements LegacyQueryInterface;
 CSSValueList implements LegacyQueryInterface;
 DOMImplementation implements LegacyQueryInterface;
 DOMParser implements LegacyQueryInterface;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ListBoxObject.webidl
@@ -0,0 +1,21 @@
+
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[NoInterfaceObject]
+interface ListBoxObject : BoxObject {
+
+  long getRowCount();
+  long getNumberOfVisibleRows();
+  long getIndexOfFirstVisibleRow();
+
+  void ensureIndexIsVisible(long rowIndex);
+  void scrollToIndex(long rowIndex);
+  void scrollByLines(long numLines);
+
+  Element? getItemAtIndex(long index);
+  long getIndexOfItem(Element item);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MenuBoxObject.webidl
@@ -0,0 +1,19 @@
+
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Func="IsChromeOrXBL"]
+interface MenuBoxObject : BoxObject {
+
+  void openMenu(boolean openFlag);
+
+  attribute Element? activeChild;
+
+  boolean handleKeyPress(KeyboardEvent keyEvent);
+
+  readonly attribute boolean openedWithKey;
+
+};
rename from layout/xul/nsIPopupBoxObject.idl
rename to dom/webidl/PopupBoxObject.webidl
--- a/layout/xul/nsIPopupBoxObject.idl
+++ b/dom/webidl/PopupBoxObject.webidl
@@ -1,84 +1,77 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsISupports.idl"
-
-interface nsIDOMElement;
-interface nsIDOMNode;
-interface nsIDOMEvent;
-interface nsIDOMClientRect;
-
-[scriptable, uuid(492861e3-d168-410f-b2bb-6eb8ce503d4a)]
-interface nsIPopupBoxObject : nsISupports
+[Func="IsChromeOrXBL"]
+interface PopupBoxObject : BoxObject
 {
   /**
    *  This method is deprecated. Use openPopup or openPopupAtScreen instead.
    */
-  void showPopup(in nsIDOMElement srcContent, in nsIDOMElement popupContent,
-                 in long xpos, in long ypos,
-                 in wstring popupType, in wstring anchorAlignment, 
-                 in wstring popupAlignment);
+  void showPopup(Element? srcContent, Element popupContent,
+                 long xpos, long ypos,
+                 DOMString popupType, DOMString anchorAlignment,
+                 DOMString popupAlignment);
 
   /**
    *  Hide the popup if it is open. The cancel argument is used as a hint that
    *  the popup is being closed because it has been cancelled, rather than
    *  something being selected within the panel.
    *
    * @param cancel if true, then the popup is being cancelled.
    */
-  void hidePopup([optional] in bool cancel);
+  void hidePopup(optional boolean cancel = false);
 
-  /** 
+  /**
    * Allow the popup to automatically position itself.
    */
   attribute boolean autoPosition;
 
   /**
    * If keyboard navigation is enabled, the keyboard may be used to navigate
    * the menuitems on the popup. Enabling keyboard navigation is the default
    * behaviour and will install capturing key event listeners on the popup
    * that do not propagate key events to the contents. If you wish to place
    * elements in a popup which accept key events, such as textboxes, keyboard
    * navigation should be disabled.
    *
    * Setting ignorekeys="true" on the popup element also disables keyboard
    * navigation, and is recommended over calling this method.
    */
-  void enableKeyboardNavigator(in boolean enableKeyboardNavigator);
+  void enableKeyboardNavigator(boolean enableKeyboardNavigator);
 
-  /** 
+  /**
    * Enable automatic popup dismissal. This only has effect when called
    * on an open popup.
    */
-  void enableRollup(in boolean enableRollup);
+  void enableRollup(boolean enableRollup);
 
   /**
    * Control whether the event that caused the popup to be automatically
    * dismissed ("rolled up") should be consumed, or dispatched as a
    * normal event.  This should be set immediately before calling showPopup()
    * if non-default behavior is desired.
    */
-  const uint32_t ROLLUP_DEFAULT = 0;   /* widget/platform default */
-  const uint32_t ROLLUP_CONSUME = 1;   /* consume the rollup event */
-  const uint32_t ROLLUP_NO_CONSUME = 2; /* don't consume the rollup event */
-  void setConsumeRollupEvent(in uint32_t consume);
+  const unsigned long ROLLUP_DEFAULT = 0;   /* widget/platform default */
+  const unsigned long ROLLUP_CONSUME = 1;   /* consume the rollup event */
+  const unsigned long ROLLUP_NO_CONSUME = 2; /* don't consume the rollup event */
+  void setConsumeRollupEvent(unsigned long consume);
 
-  /** 
+  /**
    * Size the popup to the given dimensions
    */
-  void sizeTo(in long width, in long height);
+  void sizeTo(long width, long height);
 
   /**
    * Move the popup to a point on screen in CSS pixels.
    */
-  void moveTo(in long left, in long top);
+  void moveTo(long left, long top);
 
   /**
    * Open the popup relative to a specified node at a specific location.
    *
    * The popup may be either anchored to another node or opened freely.
    * To anchor a popup to a node, supply an anchor node and set the position
    * to a string indicating the manner in which the popup should be anchored.
    * Possible values for position are:
@@ -88,17 +81,17 @@ interface nsIPopupBoxObject : nsISupport
    *
    * The anchor node does not need to be in the same document as the popup.
    *
    * If the attributesOverride argument is true, the popupanchor, popupalign
    * and position attributes on the popup node override the position value
    * argument. If attributesOverride is false, the attributes are only used
    * if position is empty.
    *
-   * For an anchored popup, the x and y arguments may be used to offset the 
+   * For an anchored popup, the x and y arguments may be used to offset the
    * popup from its anchored position by some distance, measured in CSS pixels.
    * x increases to the right and y increases down. Negative values may also
    * be used to move to the left and upwards respectively.
    *
    * Unanchored popups may be created by supplying null as the anchor node.
    * An unanchored popup appears at the position specified by x and y,
    * relative to the viewport of the document containing the popup node. In
    * this case, position and attributesOverride are ignored.
@@ -106,82 +99,75 @@ interface nsIPopupBoxObject : nsISupport
    * @param anchorElement the node to anchor the popup to, may be null
    * @param position manner is which to anchor the popup to node
    * @param x horizontal offset
    * @param y vertical offset
    * @param isContextMenu true for context menus, false for other popups
    * @param attributesOverride true if popup node attributes override position
    * @param triggerEvent the event that triggered this popup (mouse click for example)
    */
-  void openPopup(in nsIDOMElement anchorElement,
-                 in AString position,
-                 in long x, in long y,
-                 in boolean isContextMenu,
-                 in boolean attributesOverride,
-                 in nsIDOMEvent triggerEvent);
+  void openPopup(Element? anchorElement,
+                 DOMString position,
+                 long x, long y,
+                 boolean isContextMenu,
+                 boolean attributesOverride,
+                 Event? triggerEvent);
 
   /**
    * Open the popup at a specific screen position specified by x and y. This
    * position may be adjusted if it would cause the popup to be off of the
    * screen. The x and y coordinates are measured in CSS pixels, and like all
    * screen coordinates, are given relative to the top left of the primary
    * screen.
    *
    * @param isContextMenu true for context menus, false for other popups
    * @param x horizontal screen position
    * @param y vertical screen position
    * @param triggerEvent the event that triggered this popup (mouse click for example)
    */
-  void openPopupAtScreen(in long x, in long y,
-                         in boolean isContextMenu,
-                         in nsIDOMEvent triggerEvent);
+  void openPopupAtScreen(long x, long y,
+                         boolean isContextMenu,
+                         Event? triggerEvent);
 
   /**
    * Returns the state of the popup:
    *   closed - the popup is closed
    *   open - the popup is open
    *   showing - the popup is in the process of being shown
    *   hiding - the popup is in the process of being hidden
    */
-  readonly attribute AString popupState;
+  readonly attribute DOMString popupState;
 
   /**
    * The node that triggered the popup. If the popup is not open, will return
    * null.
    */
-  readonly attribute nsIDOMNode triggerNode;
+  readonly attribute Node? triggerNode;
 
   /**
    * Retrieve the anchor that was specified to openPopup or for menupopups in a
    * menu, the parent menu.
    */
-  readonly attribute nsIDOMElement anchorNode;
+  readonly attribute Element? anchorNode;
 
   /**
    * Retrieve the screen rectangle of the popup, including the area occupied by
    * any titlebar or borders present.
    */
-  nsIDOMClientRect getOuterScreenRect();
+  DOMRect getOuterScreenRect();
 
   /**
    * Move an open popup to the given anchor position. The arguments have the same
    * meaning as the corresponding argument to openPopup. This method has no effect
    * on popups that are not open.
    */
-  void moveToAnchor(in nsIDOMElement anchorElement,
-                    in AString position,
-                    in long x, in long y,
-                    in boolean attributesOverride);
+  void moveToAnchor(Element? anchorElement,
+                    DOMString position,
+                    long x, long y,
+                    boolean attributesOverride);
 
   /** Returns the alignment position where the popup has appeared relative to its
    *  anchor node or point, accounting for any flipping that occurred.
    */
-  readonly attribute AString alignmentPosition;
+  readonly attribute DOMString alignmentPosition;
   readonly attribute long alignmentOffset;
-};
 
-%{C++
-class nsIBoxObject;
-
-nsresult
-NS_NewPopupBoxObject(nsIBoxObject** aResult);
-
-%}
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ScrollBoxObject.webidl
@@ -0,0 +1,70 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[NoInterfaceObject]
+interface ScrollBoxObject : BoxObject {
+
+  /**
+   * Scroll to the given coordinates, in css pixels.
+   * (0,0) will put the top left corner of the scrolled element's padding-box
+   * at the top left corner of the scrollport (which is its inner-border-box).
+   * Values will be clamped to legal values.
+   */
+  [Throws]
+  void scrollTo(long x, long y);
+
+  /**
+   * Scroll the given amount of device pixels to the right and down.
+   * Values will be clamped to make the resuling position legal.
+   */
+  [Throws]
+  void scrollBy(long dx, long dy);
+  [Throws]
+  void scrollByLine(long dlines);
+  [Throws]
+  void scrollByIndex(long dindexes);
+  [Throws]
+  void scrollToLine(long line);
+  [Throws]
+  void scrollToElement(Element child);
+  [Throws]
+  void scrollToIndex(long index);
+
+  /**
+   * Get the current scroll position in css pixels.
+   * @see scrollTo for the definition of x and y.
+   */
+  [Pure, Throws]
+  readonly attribute long positionX;
+  [Pure, Throws]
+  readonly attribute long positionY;
+  [Pure, Throws]
+  readonly attribute long scrolledWidth;
+  [Pure, Throws]
+  readonly attribute long scrolledHeight;
+
+  /**
+   * DEPRECATED: Please use positionX and positionY
+   *
+   * Get the current scroll position in css pixels.
+   * @see scrollTo for the definition of x and y.
+   */
+  [Throws]
+  void getPosition(object x, object y);
+
+  /**
+   * DEPRECATED: Please use scrolledWidth and scrolledHeight
+   */
+  [Throws]
+  void getScrolledSize(object width, object height);
+
+  [Throws]
+  void ensureElementIsVisible(Element child);
+  [Throws]
+  void ensureIndexIsVisible(long index);
+  [Throws]
+  void ensureLineIsVisible(long line);
+};
copy from layout/xul/tree/nsITreeBoxObject.idl
copy to dom/webidl/TreeBoxObject.webidl
--- a/layout/xul/tree/nsITreeBoxObject.idl
+++ b/dom/webidl/TreeBoxObject.webidl
@@ -1,64 +1,68 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsISupports.idl"
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
 
-interface nsIDOMElement;
-interface nsITreeView;
-interface nsITreeSelection;
-interface nsITreeColumn;
-interface nsITreeColumns;
+interface MozTreeView;
+interface MozTreeColumn;
 interface nsIScriptableRegion;
 
-[scriptable, uuid(64BA5199-C4F4-4498-BBDC-F8E4C369086C)]
-interface nsITreeBoxObject : nsISupports
-{
+dictionary TreeCellInfo {
+    long row = 0;
+    MozTreeColumn? col = null;
+    DOMString childElt = "";
+};
+
+[NoInterfaceObject]
+interface TreeBoxObject : BoxObject {
+
   /**
    * Obtain the columns.
    */
-  readonly attribute nsITreeColumns columns;
+  readonly attribute TreeColumns? columns;
 
   /**
    * The view that backs the tree and that supplies it with its data.
    * It is dynamically settable, either using a view attribute on the
    * tree tag or by setting this attribute to a new value.
    */
-  attribute nsITreeView view;
+  [SetterThrows]
+  attribute MozTreeView? view;
 
   /**
    * Whether or not we are currently focused.
    */
   attribute boolean focused;
 
   /**
    * Obtain the treebody content node
    */
-  readonly attribute nsIDOMElement treeBody;
+  readonly attribute Element? treeBody;
 
   /**
    * Obtain the height of a row.
    */
   readonly attribute long rowHeight;
 
   /**
    * Obtain the width of a row.
    */
   readonly attribute long rowWidth;
 
   /**
-   * Get the pixel position of the horizontal scrollbar. 
+   * Get the pixel position of the horizontal scrollbar.
    */
   readonly attribute long horizontalPosition;
 
   /**
-   * Return the region for the visible parts of the selection, in device pixels.
+   * Return the region for the visible parts of the selection, in device pixels
    */
   readonly attribute nsIScriptableRegion selectionRegion;
 
   /**
    * Get the index of the first visible row.
    */
   long getFirstVisibleRow();
 
@@ -70,110 +74,125 @@ interface nsITreeBoxObject : nsISupports
   /**
    * Gets the number of possible visible rows.
    */
   long getPageLength();
 
   /**
    * Ensures that a row at a given index is visible.
    */
-  void ensureRowIsVisible(in long index);
+  void ensureRowIsVisible(long index);
 
   /**
    * Ensures that a given cell in the tree is visible.
    */
-  void ensureCellIsVisible(in long row, in nsITreeColumn col);
+  void ensureCellIsVisible(long row, MozTreeColumn? col);
 
   /**
    * Scrolls such that the row at index is at the top of the visible view.
    */
-  void scrollToRow(in long index);
+  void scrollToRow(long index);
 
   /**
    * Scroll the tree up or down by numLines lines. Positive
    * values move down in the tree. Prevents scrolling off the
-   * end of the tree. 
+   * end of the tree.
    */
-  void scrollByLines(in long numLines);
+  void scrollByLines(long numLines);
 
   /**
    * Scroll the tree up or down by numPages pages. A page
    * is considered to be the amount displayed by the tree.
    * Positive values move down in the tree. Prevents scrolling
    * off the end of the tree.
    */
-  void scrollByPages(in long numPages);
-  
-  /**
-   * Scrolls such that a given cell is visible (if possible) 
-   * at the top left corner of the visible view. 
-   */
-  void scrollToCell(in long row, in nsITreeColumn col);
+  void scrollByPages(long numPages);
 
   /**
-   * Scrolls horizontally so that the specified column is 
+   * Scrolls such that a given cell is visible (if possible)
+   * at the top left corner of the visible view.
+   */
+  void scrollToCell(long row, MozTreeColumn? col);
+
+  /**
+   * Scrolls horizontally so that the specified column is
    * at the left of the view (if possible).
    */
-  void scrollToColumn(in nsITreeColumn col);
+  void scrollToColumn(MozTreeColumn? col);
 
   /**
    * Scroll to a specific horizontal pixel position.
    */
-  void scrollToHorizontalPosition(in long horizontalPosition);
+  void scrollToHorizontalPosition(long horizontalPosition);
 
   /**
    * Invalidation methods for fine-grained painting control.
    */
   void invalidate();
-  void invalidateColumn(in nsITreeColumn col);
-  void invalidateRow(in long index);
-  void invalidateCell(in long row, in nsITreeColumn col);
-  void invalidateRange(in long startIndex, in long endIndex);
-  void invalidateColumnRange(in long startIndex, in long endIndex,
-                             in nsITreeColumn col);
+  void invalidateColumn(MozTreeColumn? col);
+  void invalidateRow(long index);
+  void invalidateCell(long row, MozTreeColumn? col);
+  void invalidateRange(long startIndex, long endIndex);
+  void invalidateColumnRange(long startIndex, long endIndex, MozTreeColumn? col);
 
   /**
    * A hit test that can tell you what row the mouse is over.
    * returns -1 for invalid mouse coordinates.
    *
    * The coordinate system is the client coordinate system for the
    * document this boxObject lives in, and the units are CSS pixels.
    */
-  long getRowAt(in long x, in long y);
+  long getRowAt(long x, long y);
 
   /**
-   * A hit test that can tell you what cell the mouse is over.  Row is the row index
-   * hit,  returns -1 for invalid mouse coordinates.  ColID is the column hit.
-   * ChildElt is the pseudoelement hit: this can have values of
+   * A hit test that can tell you what cell the mouse is over.
+   * TreeCellInfo.row is the row index hit,  returns -1 for invalid mouse
+   * coordinates.  TreeCellInfo.col is the column hit.
+   * TreeCellInfo.childElt is the pseudoelement hit: this can have values of
    * "cell", "twisty", "image", and "text".
    *
    * The coordinate system is the client coordinate system for the
    * document this boxObject lives in, and the units are CSS pixels.
    */
-  void getCellAt(in long x, in long y, out long row, out nsITreeColumn col, out ACString childElt);
+  [Throws]
+  TreeCellInfo getCellAt(long x, long y);
 
-  /** 
-   * Find the coordinates of an element within a specific cell. 
+  /**
+   * DEPRECATED: please use above version
+   */
+  [Throws]
+  void getCellAt(long x, long y, object row, object column, object childElt);
+
+  /**
+   * Find the coordinates of an element within a specific cell.
    */
-  void getCoordsForCellItem(in long row, in nsITreeColumn col, in ACString element, 
-                            out long x, out long y, out long width, out long height);
+  [Throws]
+  DOMRect? getCoordsForCellItem(long row, MozTreeColumn col, DOMString element);
 
-  /** 
+  /**
+   * DEPRECATED: Please use above version
+   */
+  [Throws]
+  void getCoordsForCellItem(long row, MozTreeColumn col, DOMString element,
+                            object x, object y, object width, object height);
+
+  /**
    * Determine if the text of a cell is being cropped or not.
    */
-  boolean isCellCropped(in long row, in nsITreeColumn col);
+  [Throws]
+  boolean isCellCropped(long row, MozTreeColumn? col);
 
   /**
    * The view is responsible for calling these notification methods when
    * rows are added or removed.  Index is the position at which the new
    * rows were added or at which rows were removed.  For
    * non-contiguous additions/removals, this method should be called multiple times.
    */
-  void rowCountChanged(in long index, in long count);
-  
+  void rowCountChanged(long index, long count);
+
   /**
    * Notify the tree that the view is about to perform a batch
    * update, that is, add, remove or invalidate several rows at once.
    * This must be followed by calling endUpdateBatch(), otherwise the tree
    * will get out of sync.
    */
   void beginUpdateBatch();
 
--- a/dom/webidl/TreeColumns.webidl
+++ b/dom/webidl/TreeColumns.webidl
@@ -1,21 +1,20 @@
 /* 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/. */
 
-interface MozTreeBoxObject;
 interface MozTreeColumn;
 
 [Func="IsChromeOrXBL"]
 interface TreeColumns {
   /**
    * The tree widget for these columns.
    */
-  readonly attribute MozTreeBoxObject? tree;
+  readonly attribute TreeBoxObject? tree;
 
   /**
    * The number of columns.
    */
   readonly attribute unsigned long count;
 
   /**
    * An alias for count (for the benefit of scripts which treat this as an
--- a/dom/webidl/XULDocument.webidl
+++ b/dom/webidl/XULDocument.webidl
@@ -3,17 +3,16 @@
  * 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/.
  *
  * The origin of this IDL file is:
  * dom/interfaces/xul/nsIDOMXULDocument.idl
  */
 
 interface XULCommandDispatcher;
-interface MozBoxObject;
 interface MozObserver;
 
 [Func="IsChromeOrXBL"]
 interface XULDocument : Document {
            attribute Node? popupNode;
 
   /**
    * These attributes correspond to trustedGetPopupNode().rangeOffset and
@@ -46,13 +45,13 @@ interface XULDocument : Document {
                                DOMString attr);
   void removeBroadcastListenerFor(Element broadcaster, Element observer,
                                   DOMString attr);
 
   [Throws]
   void persist([TreatNullAs=EmptyString] DOMString id, DOMString attr);
 
   [Throws]
-  MozBoxObject? getBoxObjectFor(Element? element);
+  BoxObject? getBoxObjectFor(Element? element);
 
   [Throws]
   void loadOverlay(DOMString url, MozObserver? observer);
 };
--- a/dom/webidl/XULElement.webidl
+++ b/dom/webidl/XULElement.webidl
@@ -1,15 +1,14 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-interface MozBoxObject;
 interface MozControllers;
 interface MozFrameLoader;
 interface MozRDFCompositeDataSource;
 interface MozRDFResource;
 interface MozXULTemplateBuilder;
 
 [Func="IsChromeOrXBL"]
 interface XULElement : Element {
@@ -90,17 +89,17 @@ interface XULElement : Element {
 
   readonly attribute MozRDFCompositeDataSource? database;
   readonly attribute MozXULTemplateBuilder?     builder;
   [Throws]
   readonly attribute MozRDFResource?            resource;
   [Throws]
   readonly attribute MozControllers             controllers;
   [Throws]
-  readonly attribute MozBoxObject?              boxObject;
+  readonly attribute BoxObject?                 boxObject;
 
   [Throws]
   void                      focus();
   [Throws]
   void                      blur();
   [Throws]
   void                      click();
   void                      doCommand();
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -48,16 +48,17 @@ WEBIDL_FILES = [
     'AudioTrackList.webidl',
     'AutocompleteInfo.webidl',
     'BarProp.webidl',
     'BatteryManager.webidl',
     'BeforeAfterKeyboardEvent.webidl',
     'BeforeUnloadEvent.webidl',
     'BiquadFilterNode.webidl',
     'Blob.webidl',
+    'BoxObject.webidl',
     'BrowserElementDictionaries.webidl',
     'CallsList.webidl',
     'CameraCapabilities.webidl',
     'CameraControl.webidl',
     'CameraManager.webidl',
     'CameraUtil.webidl',
     'CanvasRenderingContext2D.webidl',
     'CaretPosition.webidl',
@@ -69,16 +70,17 @@ WEBIDL_FILES = [
     'ChromeNotifications.webidl',
     'ClipboardEvent.webidl',
     'CommandEvent.webidl',
     'Comment.webidl',
     'CompositionEvent.webidl',
     'Console.webidl',
     'Constraints.webidl',
     'Contacts.webidl',
+    'ContainerBoxObject.webidl',
     'ConvolverNode.webidl',
     'Coordinates.webidl',
     'CSPReport.webidl',
     'CSS.webidl',
     'CSSPrimitiveValue.webidl',
     'CSSRuleList.webidl',
     'CSSStyleDeclaration.webidl',
     'CSSStyleSheet.webidl',
@@ -245,29 +247,31 @@ WEBIDL_FILES = [
     'InterAppConnection.webidl',
     'InterAppConnectionRequest.webidl',
     'InterAppMessagePort.webidl',
     'KeyAlgorithm.webidl',
     'KeyboardEvent.webidl',
     'KeyEvent.webidl',
     'LegacyQueryInterface.webidl',
     'LinkStyle.webidl',
+    'ListBoxObject.webidl',
     'LocalMediaStream.webidl',
     'Location.webidl',
     'MediaElementAudioSourceNode.webidl',
     'MediaError.webidl',
     'MediaList.webidl',
     'MediaQueryList.webidl',
     'MediaRecorder.webidl',
     'MediaSource.webidl',
     'MediaStream.webidl',
     'MediaStreamAudioDestinationNode.webidl',
     'MediaStreamAudioSourceNode.webidl',
     'MediaStreamTrack.webidl',
     'MediaTrackConstraintSet.webidl',
+    'MenuBoxObject.webidl',
     'MessageChannel.webidl',
     'MessageEvent.webidl',
     'MessagePort.webidl',
     'MessagePortList.webidl',
     'MimeType.webidl',
     'MimeTypeArray.webidl',
     'MouseEvent.webidl',
     'MouseScrollEvent.webidl',
@@ -315,16 +319,17 @@ WEBIDL_FILES = [
     'PerformanceResourceTiming.webidl',
     'PerformanceTiming.webidl',
     'PeriodicWave.webidl',
     'PermissionSettings.webidl',
     'PhoneNumberService.webidl',
     'Plugin.webidl',
     'PluginArray.webidl',
     'PointerEvent.webidl',
+    'PopupBoxObject.webidl',
     'Position.webidl',
     'PositionError.webidl',
     'ProcessingInstruction.webidl',
     'ProfileTimelineMarker.webidl',
     'Promise.webidl',
     'PromiseDebugging.webidl',
     'PushManager.webidl',
     'RadioNodeList.webidl',
@@ -342,16 +347,17 @@ WEBIDL_FILES = [
     'RTCPeerConnectionStatic.webidl',
     'RTCRtpReceiver.webidl',
     'RTCRtpSender.webidl',
     'RTCSessionDescription.webidl',
     'RTCStatsReport.webidl',
     'Screen.webidl',
     'ScriptProcessorNode.webidl',
     'ScrollAreaEvent.webidl',
+    'ScrollBoxObject.webidl',
     'Selection.webidl',
     'ServiceWorker.webidl',
     'ServiceWorkerContainer.webidl',
     'ServiceWorkerGlobalScope.webidl',
     'ServiceWorkerRegistration.webidl',
     'SettingChangeNotification.webidl',
     'SettingsManager.webidl',
     'ShadowRoot.webidl',
@@ -487,16 +493,17 @@ WEBIDL_FILES = [
     'TextTrackCueList.webidl',
     'TextTrackList.webidl',
     'TimeEvent.webidl',
     'TimeRanges.webidl',
     'Touch.webidl',
     'TouchEvent.webidl',
     'TouchList.webidl',
     'TransitionEvent.webidl',
+    'TreeBoxObject.webidl',
     'TreeColumns.webidl',
     'TreeWalker.webidl',
     'UDPMessageEvent.webidl',
     'UDPSocket.webidl',
     'UIEvent.webidl',
     'UndoManager.webidl',
     'URL.webidl',
     'URLSearchParams.webidl',
--- a/dom/xslt/tests/buster/buster-handlers.js
+++ b/dom/xslt/tests/buster/buster-handlers.js
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var xalan_field;
 
 function onLoad()
 {
     view.tree = document.getElementById('out');
-    view.boxObject = view.tree.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);
+    view.boxObject = view.tree.boxObject;
     {  
         view.mIframe = document.getElementById('hiddenHtml');
         view.mIframe.webNavigation.allowPlugins = false;
         view.mIframe.webNavigation.allowJavascript = false;
         view.mIframe.webNavigation.allowMetaRedirects = false;
         view.mIframe.webNavigation.allowImages = false;
     }
     view.database = view.tree.database;
--- a/editor/composer/test/test_bug434998.xul
+++ b/editor/composer/test/test_bug434998.xul
@@ -93,17 +93,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var newEditorElement = document.getElementById("editor");
     newEditorElement.makeEditable("html", true);
-    var docShell = newEditorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+    var docShell = newEditorElement.boxObject.docShell;
     progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
     progressListener = new EditorContentListener(newEditorElement);
     progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
     newEditorElement.setAttribute("src", "data:text/html,");
   }
 ]]>
 </script>
 </window>
--- a/editor/libeditor/tests/test_bug607584.xul
+++ b/editor/libeditor/tests/test_bug607584.xul
@@ -99,17 +99,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var newEditorElement = document.getElementById("editor");
     newEditorElement.makeEditable("html", true);
-    var docShell = newEditorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+    var docShell = newEditorElement.boxObject.docShell;
     progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
     progressListener = new EditorContentListener(newEditorElement);
     progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
     newEditorElement.setAttribute("src", "data:text/html,");
   }
 ]]>
 </script>
 </window>
--- a/editor/libeditor/tests/test_bug616590.xul
+++ b/editor/libeditor/tests/test_bug616590.xul
@@ -89,17 +89,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var editorElement = document.getElementById("editor");
     editorElement.makeEditable("htmlmail", true);
-    var docShell = editorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+    var docShell = editorElement.boxObject.docShell;
     progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
     progressListener = new EditorContentListener(editorElement);
     progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
     editorElement.setAttribute("src", "data:text/html,");
   }
 ]]>
 </script>
 </window>
--- a/editor/libeditor/tests/test_bug780908.xul
+++ b/editor/libeditor/tests/test_bug780908.xul
@@ -97,17 +97,17 @@ adapted from test_bug607584.xul by Kent 
       mEditor: null
   };
 
   var progress, progressListener;
 
   function runTest() {
     var newEditorElement = document.getElementById("editor");
     newEditorElement.makeEditable("html", true);
-    var docShell = newEditorElement.boxObject.QueryInterface(Components.interfaces.nsIEditorBoxObject).docShell;
+    var docShell = newEditorElement.boxObject.docShell;
     progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebProgress);
     progressListener = new EditorContentListener(newEditorElement);
     progress.addProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
     newEditorElement.setAttribute("src", "data:text/html,");
   }
 ]]>
 </script>
 </window>
--- a/extensions/cookie/test/unit/test_permmanager_defaults.js
+++ b/extensions/cookie/test/unit/test_permmanager_defaults.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // The origin we use in most of the tests.
 const TEST_ORIGIN = "example.org";
 const TEST_ORIGIN_2 = "example.com";
 const TEST_PERMISSION = "test-permission";
+Components.utils.import("resource://gre/modules/Promise.jsm");
 
 function promiseTimeout(delay) {
   let deferred = Promise.defer();
   do_timeout(delay, deferred.resolve);
   return deferred.promise;
 }
 
 function run_test() {
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -79,16 +79,17 @@ static const char *sExtensionNames[] = {
     "GL_ARB_copy_buffer",
     "GL_ARB_depth_texture",
     "GL_ARB_draw_buffers",
     "GL_ARB_draw_instanced",
     "GL_ARB_framebuffer_object",
     "GL_ARB_framebuffer_sRGB",
     "GL_ARB_half_float_pixel",
     "GL_ARB_instanced_arrays",
+    "GL_ARB_invalidate_subdata",
     "GL_ARB_map_buffer_range",
     "GL_ARB_occlusion_query2",
     "GL_ARB_pixel_buffer_object",
     "GL_ARB_robustness",
     "GL_ARB_sampler_objects",
     "GL_ARB_sync",
     "GL_ARB_texture_compression",
     "GL_ARB_texture_float",
@@ -1351,16 +1352,31 @@ GLContext::InitWithPrefix(const char *pr
             if (!LoadSymbols(&umnSymbols[0], trygl, prefix)) {
                 NS_ERROR("GL supports uniform matrix with non-square dim without supplying its functions.");
 
                 MarkUnsupported(GLFeature::uniform_matrix_nonsquare);
                 ClearSymbols(umnSymbols);
             }
         }
 
+        if (IsSupported(GLFeature::invalidate_framebuffer)) {
+            SymLoadStruct invSymbols[] = {
+                { (PRFuncPtr *) &mSymbols.fInvalidateFramebuffer,    { "InvalidateFramebuffer", nullptr } },
+                { (PRFuncPtr *) &mSymbols.fInvalidateSubFramebuffer, { "InvalidateSubFramebuffer", nullptr } },
+                END_SYMBOLS
+            };
+
+            if (!LoadSymbols(&invSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports framebuffer invalidation without supplying its functions.");
+
+                MarkUnsupported(GLFeature::invalidate_framebuffer);
+                ClearSymbols(invSymbols);
+            }
+        }
+
         if (IsExtensionSupported(KHR_debug)) {
             SymLoadStruct extSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fDebugMessageControl,  { "DebugMessageControl",  "DebugMessageControlKHR",  nullptr } },
                 { (PRFuncPtr*) &mSymbols.fDebugMessageInsert,   { "DebugMessageInsert",   "DebugMessageInsertKHR",   nullptr } },
                 { (PRFuncPtr*) &mSymbols.fDebugMessageCallback, { "DebugMessageCallback", "DebugMessageCallbackKHR", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fGetDebugMessageLog,   { "GetDebugMessageLog",   "GetDebugMessageLogKHR",   nullptr } },
                 { (PRFuncPtr*) &mSymbols.fGetPointerv,          { "GetPointerv",          "GetPointervKHR",          nullptr } },
                 { (PRFuncPtr*) &mSymbols.fPushDebugGroup,       { "PushDebugGroup",       "PushDebugGroupKHR",       nullptr } },
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -38,16 +38,17 @@
 #include "GLContextTypes.h"
 #include "GLTextureImage.h"
 #include "SurfaceTypes.h"
 #include "GLScreenBuffer.h"
 #include "GLContextSymbols.h"
 #include "base/platform_thread.h"       // for PlatformThreadId
 #include "mozilla/GenericRefCounted.h"
 #include "gfx2DGlue.h"
+#include "GeckoProfiler.h"
 
 class nsIntRegion;
 class nsIRunnable;
 class nsIThread;
 
 namespace android {
     class GraphicBuffer;
 }
@@ -95,16 +96,17 @@ MOZ_BEGIN_ENUM_CLASS(GLFeature)
     framebuffer_multisample,
     framebuffer_object,
     get_integer_indexed,
     get_integer64_indexed,
     get_query_object_iv,
     gpu_shader4,
     instanced_arrays,
     instanced_non_arrays,
+    invalidate_framebuffer,
     map_buffer_range,
     occlusion_query,
     occlusion_query_boolean,
     occlusion_query2,
     packed_depth_stencil,
     query_objects,
     renderbuffer_color_float,
     renderbuffer_color_half_float,
@@ -362,16 +364,17 @@ public:
         ARB_copy_buffer,
         ARB_depth_texture,
         ARB_draw_buffers,
         ARB_draw_instanced,
         ARB_framebuffer_object,
         ARB_framebuffer_sRGB,
         ARB_half_float_pixel,
         ARB_instanced_arrays,
+        ARB_invalidate_subdata,
         ARB_map_buffer_range,
         ARB_occlusion_query2,
         ARB_pixel_buffer_object,
         ARB_robustness,
         ARB_sampler_objects,
         ARB_sync,
         ARB_texture_compression,
         ARB_texture_float,
@@ -759,36 +762,49 @@ private:
         GLContext *tip = this;
         while (tip->mSharedContext)
             tip = tip->mSharedContext;
         return tip;
     }
 
     static void AssertNotPassingStackBufferToTheGL(const void* ptr);
 
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL                              \
+            PROFILER_LABEL_FUNC(                    \
+              js::ProfileEntry::Category::GRAPHICS);\
+            BeforeGLCall(MOZ_FUNCTION_NAME)
+#else
 #define BEFORE_GL_CALL                              \
             do {                                    \
                 BeforeGLCall(MOZ_FUNCTION_NAME);    \
             } while (0)
+#endif
 
 #define AFTER_GL_CALL                               \
             do {                                    \
                 AfterGLCall(MOZ_FUNCTION_NAME);     \
             } while (0)
 
 #define TRACKING_CONTEXT(a)                         \
             do {                                    \
                 TrackingContext()->a;               \
             } while (0)
 
 #define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) AssertNotPassingStackBufferToTheGL(ptr)
 
 #else // ifdef DEBUG
 
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS)
+#else
 #define BEFORE_GL_CALL do { } while (0)
+#endif
 #define AFTER_GL_CALL do { } while (0)
 #define TRACKING_CONTEXT(a) do {} while (0)
 #define ASSERT_NOT_PASSING_STACK_BUFFER_TO_GL(ptr) do {} while (0)
 
 #endif // ifdef DEBUG
 
 #define ASSERT_SYMBOL_PRESENT(func) \
             do {\
@@ -885,16 +901,30 @@ public:
             default:
                 // Nothing we care about, likely an error.
                 break;
         }
 
         raw_fBindFramebuffer(target, framebuffer);
     }
 
+    void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fInvalidateFramebuffer);
+        mSymbols.fInvalidateFramebuffer(target, numAttachments, attachments);
+        AFTER_GL_CALL;
+    }
+
+    void fInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fInvalidateSubFramebuffer);
+        mSymbols.fInvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height);
+        AFTER_GL_CALL;
+    }
+
     void fBindTexture(GLenum target, GLuint texture) {
         BEFORE_GL_CALL;
         mSymbols.fBindTexture(target, texture);
         AFTER_GL_CALL;
     }
 
     void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
         BEFORE_GL_CALL;
@@ -3532,16 +3562,20 @@ public:
     /* Clear to transparent black, with 0 depth and stencil,
      * while preserving current ClearColor etc. values.
      * Useful for resizing offscreen buffers.
      */
     void ClearSafely();
 
     bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
 
+    bool IsDrawingToDefaultFramebuffer() {
+        return Screen()->IsDrawFramebufferDefault();
+    }
+
 protected:
     nsRefPtr<TextureGarbageBin> mTexGarbageBin;
 
 public:
     TextureGarbageBin* TexGarbageBin() {
         MOZ_ASSERT(mTexGarbageBin);
         return mTexGarbageBin;
     }
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -284,16 +284,25 @@ static const FeatureInfo sFeatureInfoArr
         }
         /* This is an expanded version of `instanced_arrays` that allows for all
          * enabled active attrib arrays to have non-zero divisors.
          * ANGLE_instanced_arrays and NV_instanced_arrays forbid this, but GLES3
          * has no such restriction.
          */
     },
     {
+        "invalidate_framebuffer",
+        430, // OpenGL version
+        300, // OpenGL ES version
+        GLContext::ARB_invalidate_subdata,
+        {
+            GLContext::Extensions_End
+        }
+    },
+    {
         "map_buffer_range",
         300, // OpenGL version
         300, // OpenGL ES version
         GLContext::ARB_map_buffer_range,
         {
             GLContext::Extensions_End
         }
     },
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -329,16 +329,21 @@ struct GLContextSymbols
     PFNGLISFRAMEBUFFER fIsFramebuffer;
     typedef realGLboolean (GLAPIENTRY * PFNGLISRENDERBUFFER) (GLuint renderbuffer);
     PFNGLISRENDERBUFFER fIsRenderbuffer;
     typedef realGLboolean (GLAPIENTRY * PFNGLISVERTEXARRAY) (GLuint array);
     PFNGLISVERTEXARRAY fIsVertexArray;
     typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
     PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
 
+    typedef void (GLAPIENTRY * PFNINVALIDATEFRAMEBUFFER) (GLenum target, GLsizei numAttachments, const GLenum* attachments);
+    PFNINVALIDATEFRAMEBUFFER fInvalidateFramebuffer;
+    typedef void (GLAPIENTRY * PFNINVALIDATESUBFRAMEBUFFER) (GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+    PFNINVALIDATESUBFRAMEBUFFER fInvalidateSubFramebuffer;
+
         // These functions are only used by Skia/GL in desktop mode.
         // Other parts of Gecko should avoid using these
         typedef void (GLAPIENTRY * PFNGLCLIENTACTIVETEXTURE) (GLenum texture);
         PFNGLCLIENTACTIVETEXTURE fClientActiveTexture;
         typedef void (GLAPIENTRY * PFNDISABLECLIENTSTATE) (GLenum capability);
         PFNDISABLECLIENTSTATE fDisableClientState;
         typedef void (GLAPIENTRY * PFNENABLECLIENTSTATE) (GLenum capability);
         PFNENABLECLIENTSTATE fEnableClientState;
--- a/gfx/gl/GLLibraryEGL.h
+++ b/gfx/gl/GLLibraryEGL.h
@@ -7,16 +7,17 @@
 
 #if defined(MOZ_X11)
 #include "mozilla/X11Util.h"
 #endif
 
 #include "GLLibraryLoader.h"
 #include "mozilla/ThreadLocal.h"
 #include "nsIFile.h"
+#include "GeckoProfiler.h"
 
 #include <bitset>
 
 #if defined(XP_WIN)
 
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN 1
 #endif
@@ -70,27 +71,38 @@ namespace gl {
 #  define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__
 # elif defined(_MSC_VER)
 #  define MOZ_FUNCTION_NAME __FUNCTION__
 # else
 #  define MOZ_FUNCTION_NAME __func__  // defined in C99, supported in various C++ compilers. Just raw function name.
 # endif
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL                      \
+    PROFILER_LABEL_FUNC(                    \
+      js::ProfileEntry::Category::GRAPHICS);\
+    BeforeGLCall(MOZ_FUNCTION_NAME)
+#else
 #define BEFORE_GL_CALL do {          \
     BeforeGLCall(MOZ_FUNCTION_NAME); \
 } while (0)
+#endif
 
 #define AFTER_GL_CALL do {           \
     AfterGLCall(MOZ_FUNCTION_NAME);  \
 } while (0)
-// We rely on the fact that GLLibraryEGL.h #defines BEFORE_GL_CALL and
-// AFTER_GL_CALL to nothing if !defined(DEBUG).
+#else
+#ifdef MOZ_WIDGET_ANDROID
+// Record the name of the GL call for better hang stacks on Android.
+#define BEFORE_GL_CALL PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS)
 #else
 #define BEFORE_GL_CALL
+#endif
 #define AFTER_GL_CALL
 #endif
 
 class GLLibraryEGL
 {
 public:
     GLLibraryEGL() 
         : mInitialized(false),
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -524,16 +524,30 @@ GLScreenBuffer::Readback(SharedSurface* 
   }
 
   if (needsSwap) {
       src->UnlockProd();
       SharedSurf()->LockProd();
   }
 }
 
+bool
+GLScreenBuffer::IsDrawFramebufferDefault() const
+{
+    if (!mDraw)
+        return IsReadFramebufferDefault();
+    return mDraw->mFB == 0;
+}
+
+bool
+GLScreenBuffer::IsReadFramebufferDefault() const
+{
+    return SharedSurf()->mAttachType == AttachmentType::Screen;
+}
+
 ////////////////////////////////////////////////////////////////////////
 // DrawBuffer
 
 bool
 DrawBuffer::Create(GLContext* const gl,
                    const SurfaceCaps& caps,
                    const GLFormats& formats,
                    const gfx::IntSize& size,
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -256,14 +256,17 @@ public:
     GLuint GetDrawFB() const;
     GLuint GetReadFB() const;
 
     // Here `fb` is the actual framebuffer you want bound. Binding 0 will
     // bind the (generally useless) default framebuffer.
     void BindFB_Internal(GLuint fb);
     void BindDrawFB_Internal(GLuint fb);
     void BindReadFB_Internal(GLuint fb);
+
+    bool IsDrawFramebufferDefault() const;
+    bool IsReadFramebufferDefault() const;
 };
 
 }   // namespace gl
 }   // namespace mozilla
 
 #endif  // SCREEN_BUFFER_H_
--- a/gfx/gl/SharedSurface.cpp
+++ b/gfx/gl/SharedSurface.cpp
@@ -1,17 +1,19 @@
 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SharedSurface.h"
 
+#include "../2d/2D.h"
 #include "GLBlitHelper.h"
 #include "GLContext.h"
+#include "GLReadTexImageHelper.h"
 #include "nsThreadUtils.h"
 #include "ScopedGLHelpers.h"
 #include "SharedSurfaceGL.h"
 
 namespace mozilla {
 namespace gl {
 
 /*static*/ void
@@ -442,10 +444,111 @@ ScopedReadbackFB::~ScopedReadbackFB()
     if (mSurfToUnlock) {
         mSurfToUnlock->UnlockProd();
     }
     if (mSurfToLock) {
         mSurfToLock->LockProd();
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+class AutoLockBits
+{
+    gfx::DrawTarget* mDT;
+    uint8_t* mLockedBits;
+
+public:
+    AutoLockBits(gfx::DrawTarget* dt)
+        : mDT(dt)
+        , mLockedBits(nullptr)
+    {
+        MOZ_ASSERT(mDT);
+    }
+
+    bool Lock(uint8_t** data, gfx::IntSize* size, int32_t* stride,
+              gfx::SurfaceFormat* format)
+    {
+        bool success = mDT->LockBits(data, size, stride, format);
+        if (success)
+            mLockedBits = *data;
+        return success;
+    }
+
+    ~AutoLockBits() {
+        if (mLockedBits)
+            mDT->ReleaseBits(mLockedBits);
+    }
+};
+
+bool
+ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst)
+{
+    AutoLockBits lock(dst);
+
+    uint8_t* dstBytes;
+    gfx::IntSize dstSize;
+    int32_t dstStride;
+    gfx::SurfaceFormat dstFormat;
+    if (!dst->LockBits(&dstBytes, &dstSize, &dstStride, &dstFormat))
+        return false;
+
+    const bool isDstRGBA = (dstFormat == gfx::SurfaceFormat::R8G8B8A8 ||
+                            dstFormat == gfx::SurfaceFormat::R8G8B8X8);
+    MOZ_ASSERT_IF(!isDstRGBA, dstFormat == gfx::SurfaceFormat::B8G8R8A8 ||
+                              dstFormat == gfx::SurfaceFormat::B8G8R8X8);
+
+    size_t width = src->mSize.width;
+    size_t height = src->mSize.height;
+    MOZ_ASSERT(width == (size_t)dstSize.width);
+    MOZ_ASSERT(height == (size_t)dstSize.height);
+
+    GLenum readGLFormat;
+    GLenum readType;
+
+    {
+        ScopedReadbackFB autoReadback(src);
+
+
+        // We have a source FB, now we need a format.
+        GLenum dstGLFormat = isDstRGBA ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
+        GLenum dstType = LOCAL_GL_UNSIGNED_BYTE;
+
+        // We actually don't care if they match, since we can handle
+        // any read{Format,Type} we get.
+        GLContext* gl = src->mGL;
+        GetActualReadFormats(gl, dstGLFormat, dstType, &readGLFormat,
+                             &readType);
+
+        MOZ_ASSERT(readGLFormat == LOCAL_GL_RGBA ||
+                   readGLFormat == LOCAL_GL_BGRA);
+        MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
+
+        // ReadPixels from the current FB into lockedBits.
+        {
+            size_t alignment = 8;
+            if (dstStride % 4 == 0)
+                alignment = 4;
+            ScopedPackAlignment autoAlign(gl, alignment);
+
+            gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType,
+                                dstBytes);
+        }
+    }
+
+    const bool isReadRGBA = readGLFormat == LOCAL_GL_RGBA;
+
+    if (isReadRGBA != isDstRGBA) {
+        for (size_t j = 0; j < height; ++j) {
+            uint8_t* rowItr = dstBytes + j*dstStride;
+            uint8_t* rowEnd = rowItr + 4*width;
+            while (rowItr != rowEnd) {
+                Swap(rowItr[0], rowItr[2]);
+                rowItr += 4;
+            }
+        }
+    }
+
+    return true;
+}
+
 } /* namespace gfx */
 } /* namespace mozilla */
--- a/gfx/gl/SharedSurface.h
+++ b/gfx/gl/SharedSurface.h
@@ -26,16 +26,19 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "ScopedGLHelpers.h"
 #include "SurfaceTypes.h"
 
 class nsIThread;
 
 namespace mozilla {
+namespace gfx {
+class DrawTarget;
+}
 namespace gl {
 
 class GLContext;
 class SurfaceFactory;
 class ShSurfHandle;
 
 class SharedSurface
 {
@@ -248,12 +251,14 @@ class ScopedReadbackFB
     SharedSurface* mSurfToUnlock;
     SharedSurface* mSurfToLock;
 
 public:
     ScopedReadbackFB(SharedSurface* src);
     ~ScopedReadbackFB();
 };
 
+bool ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst);
+
 } // namespace gl
 } // namespace mozilla
 
 #endif // SHARED_SURFACE_H_
--- a/gfx/gl/SharedSurfaceGL.cpp
+++ b/gfx/gl/SharedSurfaceGL.cpp
@@ -78,85 +78,29 @@ SharedSurface_Basic::SharedSurface_Basic
     mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
                               LOCAL_GL_COLOR_ATTACHMENT0,
                               LOCAL_GL_TEXTURE_2D,
                               mTex,
                               0);
 
     DebugOnly<GLenum> status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
-
-    int32_t stride = gfx::GetAlignedStride<4>(size.width * BytesPerPixel(format));
-    mData = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
-    // Leave the extra return for clarity, in case we decide more code should
-    // be added after this check, that should run even if mData is null.
-    if (NS_WARN_IF(!mData)) {
-        return;
-    }
 }
 
 SharedSurface_Basic::~SharedSurface_Basic()
 {
     if (!mGL->MakeCurrent())
         return;
 
     if (mFB)
         mGL->fDeleteFramebuffers(1, &mFB);
 
     mGL->fDeleteTextures(1, &mTex);
 }
 
-void
-SharedSurface_Basic::Fence()
-{
-    // The constructor can fail to get us mData, we should deal with it:
-    if (NS_WARN_IF(!mData)) {
-        return;
-    }
-
-    mGL->MakeCurrent();
-    ScopedBindFramebuffer autoFB(mGL, mFB);
-    ReadPixelsIntoDataSurface(mGL, mData);
-}
-
-bool
-SharedSurface_Basic::WaitSync()
-{
-    return true;
-}
-
-bool
-SharedSurface_Basic::PollSync()
-{
-    return true;
-}
-
-void
-SharedSurface_Basic::Fence_ContentThread_Impl()
-{
-}
-
-bool
-SharedSurface_Basic::WaitSync_ContentThread_Impl()
-{
-    mGL->MakeCurrent();
-    ScopedBindFramebuffer autoFB(mGL, mFB);
-    ReadPixelsIntoDataSurface(mGL, mData);
-    return true;
-}
-
-bool
-SharedSurface_Basic::PollSync_ContentThread_Impl()
-{
-    mGL->MakeCurrent();
-    ScopedBindFramebuffer autoFB(mGL, mFB);
-    ReadPixelsIntoDataSurface(mGL, mData);
-    return true;
-}
-
 ////////////////////////////////////////////////////////////////////////
 // SharedSurface_GLTexture
 
 /*static*/ UniquePtr<SharedSurface_GLTexture>
 SharedSurface_GLTexture::Create(GLContext* prodGL,
                                 GLContext* consGL,
                                 const GLFormats& formats,
                                 const IntSize& size,
--- a/gfx/gl/SharedSurfaceGL.h
+++ b/gfx/gl/SharedSurfaceGL.h
@@ -42,47 +42,36 @@ public:
         MOZ_ASSERT(surf->mType == SharedSurfaceType::Basic);
 
         return (SharedSurface_Basic*)surf;
     }
 
 protected:
     const GLuint mTex;
     GLuint mFB;
-    RefPtr<gfx::DataSourceSurface> mData;
 
     SharedSurface_Basic(GLContext* gl,
                         const gfx::IntSize& size,
                         bool hasAlpha,
                         gfx::SurfaceFormat format,
                         GLuint tex);
 
 public:
     virtual ~SharedSurface_Basic();
 
     virtual void LockProdImpl() MOZ_OVERRIDE {}
     virtual void UnlockProdImpl() MOZ_OVERRIDE {}
 
-
-    virtual void Fence() MOZ_OVERRIDE;
-    virtual bool WaitSync() MOZ_OVERRIDE;
-    virtual bool PollSync() MOZ_OVERRIDE;
-
-    virtual void Fence_ContentThread_Impl() MOZ_OVERRIDE;
-    virtual bool WaitSync_ContentThread_Impl() MOZ_OVERRIDE;
-    virtual bool PollSync_ContentThread_Impl() MOZ_OVERRIDE;
+    virtual void Fence() MOZ_OVERRIDE {}
+    virtual bool WaitSync() MOZ_OVERRIDE { return true; }
+    virtual bool PollSync() MOZ_OVERRIDE { return true; }
 
     virtual GLuint ProdTexture() MOZ_OVERRIDE {
         return mTex;
     }
-
-    // Implementation-specific functions below:
-    gfx::DataSourceSurface* GetData() {
-        return mData;
-    }
 };
 
 class SurfaceFactory_Basic
     : public SurfaceFactory
 {
 public:
     SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps)
         : SurfaceFactory(gl, SharedSurfaceType::Basic, caps)
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -111,99 +111,70 @@ CanvasLayerD3D10::UpdateSurface()
   } else if (mIsD2DTexture) {
     return;
   }
 
   if (!mTexture) {
     return;
   }
 
+  SharedSurface* surf = nullptr;
   if (mGLContext) {
     auto screen = mGLContext->Screen();
     MOZ_ASSERT(screen);
 
-    SharedSurface* surf = screen->Front()->Surf();
+    surf = screen->Front()->Surf();
     if (!surf)
       return;
     surf->WaitSync();
 
-    switch (surf->mType) {
-      case SharedSurfaceType::EGLSurfaceANGLE: {
-        SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
-        HANDLE shareHandle = shareSurf->GetShareHandle();
-
-        HRESULT hr = device()->OpenSharedResource(shareHandle,
-                                                  __uuidof(ID3D10Texture2D),
-                                                  getter_AddRefs(mTexture));
-        if (FAILED(hr))
-          return;
+    if (surf->mType == SharedSurfaceType::EGLSurfaceANGLE) {
+      SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
+      HANDLE shareHandle = shareSurf->GetShareHandle();
 
-        hr = device()->CreateShaderResourceView(mTexture,
-                                                nullptr,
-                                                getter_AddRefs(mSRView));
-        if (FAILED(hr))
-          return;
-
+      HRESULT hr = device()->OpenSharedResource(shareHandle,
+                                                __uuidof(ID3D10Texture2D),
+                                                getter_AddRefs(mTexture));
+      if (FAILED(hr))
         return;
-      }
-      case SharedSurfaceType::Basic: {
-        SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
-        // WebGL reads entire surface.
-        D3D10_MAPPED_TEXTURE2D map;
 
-        HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
+      hr = device()->CreateShaderResourceView(mTexture,
+                                              nullptr,
+                                              getter_AddRefs(mSRView));
+      if (FAILED(hr))
+        return;
 
-        if (FAILED(hr)) {
-          NS_WARNING("Failed to map CanvasLayer texture.");
-          return;
-        }
+      return;
+    }
+  }
+
+  D3D10_MAPPED_TEXTURE2D map;
+  HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
 
-        DataSourceSurface* frameData = shareSurf->GetData();
-        // Scope for DrawTarget, so it's destroyed before Unmap.
-        {
-          IntSize boundsSize(mBounds.width, mBounds.height);
-          RefPtr<DrawTarget> mapDt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
-                                                                      (uint8_t*)map.pData,
-                                                                      boundsSize,
-                                                                      map.RowPitch,
-                                                                      SurfaceFormat::B8G8R8A8);
+  if (FAILED(hr)) {
+    NS_WARNING("Failed to lock CanvasLayer texture.");
+    return;
+  }
 
-          Rect drawRect(0, 0, frameData->GetSize().width, frameData->GetSize().height);
-          mapDt->DrawSurface(frameData, drawRect, drawRect,
-                             DrawSurfaceOptions(),  DrawOptions(1.0F, CompositionOp::OP_SOURCE));
-          mapDt->Flush();
-        }
+  RefPtr<DrawTarget> destTarget =
+    Factory::CreateDrawTargetForD3D10Texture(mTexture,
+                                             SurfaceFormat::R8G8B8A8);
 
-        mTexture->Unmap(0);
-        mSRView = mUploadSRView;
-        break;
-      }
-
-      default:
-        MOZ_CRASH("Unhandled SharedSurfaceType.");
+  if (surf) {
+    if (!ReadbackSharedSurface(surf, destTarget)) {
+      NS_WARNING("Failed to readback into texture.");
     }
   } else if (mSurface) {
-    D3D10_MAPPED_TEXTURE2D map;
-    HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);
-
-    if (FAILED(hr)) {
-      NS_WARNING("Failed to lock CanvasLayer texture.");
-      return;
-    }
-
-    RefPtr<DrawTarget> destTarget =
-      Factory::CreateDrawTargetForD3D10Texture(mTexture,
-                                               SurfaceFormat::R8G8B8A8);
     Rect r(Point(0, 0), ToRect(mBounds).Size());
     destTarget->DrawSurface(mSurface, r, r, DrawSurfaceOptions(),
                             DrawOptions(1.0F, CompositionOp::OP_SOURCE));
+  }
 
-    mTexture->Unmap(0);
-    mSRView = mUploadSRView;
-  }
+  mTexture->Unmap(0);
+  mSRView = mUploadSRView;
 }
 
 Layer*
 CanvasLayerD3D10::GetLayer()
 {
   return this;
 }
 
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -71,52 +71,52 @@ CanvasLayerD3D9::UpdateSurface()
     CreateTexture();
 
     if (!mTexture) {
       NS_WARNING("CanvasLayerD3D9::Updated called but no texture present and creation failed!");
       return;
     }
   }
 
-  RefPtr<SourceSurface> surface;
-
-  if (mGLContext) {
-    auto screen = mGLContext->Screen();
-    MOZ_ASSERT(screen);
-
-    SharedSurface* surf = screen->Front()->Surf();
-    if (!surf)
-      return;
-    surf->WaitSync();
-
-    SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
-    surface = shareSurf->GetData();
-  } else {
-    surface = mDrawTarget->Snapshot();
-  }
-
   // WebGL reads entire surface.
   LockTextureRectD3D9 textureLock(mTexture);
   if (!textureLock.HasLock()) {
     NS_WARNING("Failed to lock CanvasLayer texture.");
     return;
   }
 
   D3DLOCKED_RECT rect = textureLock.GetLockRect();
   IntSize boundsSize(mBounds.width, mBounds.height);
   RefPtr<DrawTarget> rectDt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                                                (uint8_t*)rect.pBits,
                                                                boundsSize,
                                                                rect.Pitch,
                                                                SurfaceFormat::B8G8R8A8);
 
-  Rect drawRect(0, 0, surface->GetSize().width, surface->GetSize().height);
-  rectDt->DrawSurface(surface, drawRect, drawRect,
-                      DrawSurfaceOptions(),  DrawOptions(1.0F, CompositionOp::OP_SOURCE));
-  rectDt->Flush();
+  if (mGLContext) {
+    auto screen = mGLContext->Screen();
+    MOZ_ASSERT(screen);
+
+    SharedSurface* surf = screen->Front()->Surf();
+    if (!surf)
+      return;
+    surf->WaitSync();
+
+    if (!ReadbackSharedSurface(surf, rectDt)) {
+      NS_WARNING("Failed to readback into texture.");
+    }
+  } else {
+    RefPtr<SourceSurface> surface = mDrawTarget->Snapshot();
+
+    Rect drawRect(0, 0, surface->GetSize().width, surface->GetSize().height);
+    rectDt->DrawSurface(surface, drawRect, drawRect,
+                        DrawSurfaceOptions(),  DrawOptions(1.0F, CompositionOp::OP_SOURCE));
+
+    rectDt->Flush();
+  }
 }
 
 Layer*
 CanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
--- a/gfx/tests/unit/test_nsIScriptableRegion.js
+++ b/gfx/tests/unit/test_nsIScriptableRegion.js
@@ -1,16 +1,10 @@
 function run_test()
 {
-  // XXX Work around for the fact that for non-libxul builds loading gfx
-  // components doesn't call up the layout initialisation routine. This should
-  // be fixed/improved by bug 515595.
-  Components.classes["@mozilla.org/layout/xul-boxobject-tree;1"]
-            .createInstance(Components.interfaces.nsIBoxObject);
-
   let rgn = Components.classes["@mozilla.org/gfx/region;1"].createInstance(Components.interfaces.nsIScriptableRegion);
   do_check_true (rgn.getRects() === null)
   rgn.unionRect(0,0,80,60);
   do_check_true (rgn.getRects().toString() == "0,0,80,60")
   rgn.unionRect(90,70,1,1);
   do_check_true (rgn.getRects().toString() == "0,0,80,60,90,70,1,1")
 }
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1899,17 +1899,17 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint
         // vertical baseline). The adjustment here is somewhat ad hoc; we
         // should eventually look for baseline tables[1] in the fonts and use
         // those if available.
         // [1] http://www.microsoft.com/typography/otspec/base.htm
         aRunParams.context->SetMatrix(aRunParams.context->CurrentMatrix().
             Translate(p).       // translate origin for rotation
             Rotate(M_PI / 2.0). // turn 90deg clockwise
             Translate(-p).      // undo the translation
-            Translate(gfxPoint(0, metrics.emAscent - metrics.emDescent) / 2));
+            Translate(gfxPoint(0, (metrics.emAscent - metrics.emDescent) / 2)));
                                 // and offset the (alphabetic) baseline of the
                                 // horizontally-shaped text from the (centered)
                                 // default baseline used for vertical
     }
 
     nsAutoPtr<gfxTextContextPaint> contextPaint;
     if (fontParams.haveSVGGlyphs && !fontParams.contextPaint) {
         // If no pattern is specified for fill, use the current pattern
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -989,16 +989,17 @@ gfxFontEntry::InputsForOpenTypeFeature(i
         hb_ot_layout_collect_lookups(face, kGSUB, scriptTags, nullptr,
                                      features, featurelookups);
         hb_codepoint_t index = -1;
         while (hb_set_next(featurelookups, &index)) {
             hb_ot_layout_lookup_collect_glyphs(face, kGSUB, index,
                                                nullptr, inputGlyphs,
                                                nullptr, nullptr);
         }
+        hb_set_destroy(featurelookups);
     }
 
     hb_face_destroy(face);
 
     mFeatureInputs->Put(scriptFeature, inputGlyphs);
     return inputGlyphs;
 }
 
--- a/ipc/chromium/src/base/process_util_win.cc
+++ b/ipc/chromium/src/base/process_util_win.cc
@@ -12,16 +12,17 @@
 #include <winternl.h>
 #include <psapi.h>
 
 #include "base/histogram.h"
 #include "base/logging.h"
 #include "base/win_util.h"
 
 #include <algorithm>
+#include "prenv.h"
 
 namespace {
 
 // System pagesize. This value remains constant on x86/64 architectures.
 const int PAGESIZE_KB = 4;
 
 // HeapSetInformation function pointer.
 typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
@@ -270,20 +271,19 @@ void FreeThreadAttributeList(LPPROC_THRE
 bool LaunchApp(const std::wstring& cmdline,
                bool wait, bool start_hidden, ProcessHandle* process_handle) {
 
   // We want to inherit the std handles so dump() statements and assertion
   // messages in the child process can be seen - but we *do not* want to
   // blindly have all handles inherited.  Vista and later has a technique
   // where only specified handles are inherited - so we use this technique if
   // we can.  If that technique isn't available (or it fails), we just don't
-  // inherit anything.  This means that dump() etc isn't going to be seen on
-  // XP release builds, but that's OK (developers who really care can run a
-  // debug build on XP, where the processes are marked as "console" apps, so
-  // things work without these hoops)
+  // inherit anything.  This can cause us a problem for Windows XP testing,
+  // because we sometimes need the handles to get inherited for test logging to
+  // work. So we also inherit when a specific environment variable is set.
   DWORD dwCreationFlags = 0;
   BOOL bInheritHandles = FALSE;
   // We use a STARTUPINFOEX, but if we can't do the thread attribute thing, we
   // just pass the size of a STARTUPINFO.
   STARTUPINFOEX startup_info_ex;
   ZeroMemory(&startup_info_ex, sizeof(startup_info_ex));
   STARTUPINFO &startup_info = startup_info_ex.StartupInfo;
   startup_info.cb = sizeof(startup_info);
@@ -300,31 +300,40 @@ bool LaunchApp(const std::wstring& cmdli
     HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
     HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
 
     if (IsInheritableHandle(stdOut))
       handlesToInherit[handleCount++] = stdOut;
     if (stdErr != stdOut && IsInheritableHandle(stdErr))
       handlesToInherit[handleCount++] = stdErr;
 
-    if (handleCount)
+    if (handleCount) {
       lpAttributeList = CreateThreadAttributeList(handlesToInherit, handleCount);
-  }
-
-  if (lpAttributeList) {
-    // it's safe to inherit handles, so arrange for that...
-    startup_info.cb = sizeof(startup_info_ex);
+      if (lpAttributeList) {
+        // it's safe to inherit handles, so arrange for that...
+        startup_info.cb = sizeof(startup_info_ex);
+        startup_info.dwFlags |= STARTF_USESTDHANDLES;
+        startup_info.hStdOutput = stdOut;
+        startup_info.hStdError = stdErr;
+        startup_info.hStdInput = INVALID_HANDLE_VALUE;
+        startup_info_ex.lpAttributeList = lpAttributeList;
+        dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
+        bInheritHandles = TRUE;
+      }
+    }
+  } else if (PR_GetEnv("MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA")) {
+    // Even if we can't limit what gets inherited, we sometimes want to inherit
+    // stdout/err for testing purposes.
     startup_info.dwFlags |= STARTF_USESTDHANDLES;
     startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
     startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
     startup_info.hStdInput = INVALID_HANDLE_VALUE;
-    startup_info_ex.lpAttributeList = lpAttributeList;
-    dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
     bInheritHandles = TRUE;
   }
+
   PROCESS_INFORMATION process_info;
   BOOL createdOK = CreateProcess(NULL,
                      const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
                      bInheritHandles, dwCreationFlags, NULL, NULL,
                      &startup_info, &process_info);
   if (lpAttributeList)
     FreeThreadAttributeList(lpAttributeList);
   if (!createdOK)
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -3,17 +3,16 @@ dnl Local autoconf macros used with mozi
 dnl The contents of this file are under the Public Domain.
 dnl
 
 builtin(include, ../../build/autoconf/hotfixes.m4)dnl
 builtin(include, ../../build/autoconf/acwinpaths.m4)dnl
 builtin(include, ../../build/autoconf/hooks.m4)dnl
 builtin(include, ../../build/autoconf/config.status.m4)dnl
 builtin(include, ../../build/autoconf/toolchain.m4)dnl
-builtin(include, ../../build/autoconf/ccache.m4)dnl
 builtin(include, ../../build/autoconf/wrapper.m4)dnl
 builtin(include, ../../build/autoconf/pkg.m4)dnl
 builtin(include, ../../build/autoconf/nspr.m4)dnl
 builtin(include, ../../build/autoconf/nspr-build.m4)dnl
 builtin(include, ../../build/autoconf/codeset.m4)dnl
 builtin(include, ../../build/autoconf/altoptions.m4)dnl
 builtin(include, ../../build/autoconf/mozprog.m4)dnl
 builtin(include, ../../build/autoconf/mozheader.m4)dnl
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -2004,17 +2004,20 @@ IsCoercionCall(ModuleCompiler &m, ParseN
     return false;
 }
 
 static bool
 IsFloatLiteral(ModuleCompiler &m, ParseNode *pn)
 {
     ParseNode *coercedExpr;
     AsmJSCoercion coercion;
-    if (!IsCoercionCall(m, pn, &coercion, &coercedExpr) || coercion != AsmJS_FRound)
+    if (!IsCoercionCall(m, pn, &coercion, &coercedExpr))
+        return false;
+    // Don't fold into || to avoid clang/memcheck bug (bug 1077031).
+    if (coercion != AsmJS_FRound)
         return false;
     return IsNumericNonFloatLiteral(coercedExpr);
 }
 
 static unsigned
 SimdTypeToLength(AsmJSSimdType type)
 {
     switch (type) {
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3437,18 +3437,16 @@ MOZ_ARG_ENABLE_BOOL(oom-breakpoint,
 [  --enable-oom-breakpoint
                           Enable a breakpoint function for artificial OOMs],
     JS_OOM_BREAKPOINT=1,
     JS_OOM_BREAKPOINT= )
 if test -n "$JS_OOM_BREAKPOINT"; then
     AC_DEFINE(JS_OOM_BREAKPOINT)
 fi
 
-MOZ_CHECK_CCACHE
-
 dnl ========================================================
 dnl = Enable static checking using gcc-dehydra
 dnl ========================================================
 
 MOZ_ARG_WITH_STRING(static-checking,
 [  --with-static-checking=path/to/gcc_dehydra.so
                           Enable static checking of code using GCC-dehydra],
     DEHYDRA_PATH=$withval,
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -2,18 +2,16 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef gc_GCRuntime_h
 #define gc_GCRuntime_h
 
-#include <setjmp.h>
-
 #include "jsgc.h"
 
 #include "gc/Heap.h"
 #ifdef JSGC_GENERATIONAL
 # include "gc/Nursery.h"
 #endif
 #include "gc/Statistics.h"
 #ifdef JSGC_GENERATIONAL
@@ -60,52 +58,16 @@ class ChunkPool
         inline void popFront();
         inline void removeAndPopFront();
       private:
         ChunkPool &pool;
         Chunk **chunkp;
     };
 };
 
-struct ConservativeGCData
-{
-    /*
-     * The GC scans conservatively between ThreadData::nativeStackBase and
-     * nativeStackTop unless the latter is nullptr.
-     */
-    uintptr_t           *nativeStackTop;
-
-    union {
-        jmp_buf         jmpbuf;
-        uintptr_t       words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))];
-    } registerSnapshot;
-
-    ConservativeGCData() {
-        mozilla::PodZero(this);
-    }
-
-    ~ConservativeGCData() {
-        /*
-         * The conservative GC scanner should be disabled when the thread leaves
-         * the last request.
-         */
-        MOZ_ASSERT(!hasStackToScan());
-    }
-
-    MOZ_NEVER_INLINE void recordStackTop();
-
-    void updateForRequestEnd() {
-        nativeStackTop = nullptr;
-    }
-
-    bool hasStackToScan() const {
-        return !!nativeStackTop;
-    }
-};
-
 /*
  * Encapsulates all of the GC tunables. These are effectively constant and
  * should only be modified by setParameter.
  */
 class GCSchedulingTunables
 {
     /*
      * Soft limit on the number of bytes we are allowed to allocate in the GC
@@ -318,18 +280,16 @@ class GCRuntime
     void setDeterministic(bool enable);
 #endif
 
     size_t maxMallocBytesAllocated() { return maxMallocBytes; }
 
   public:
     // Internal public interface
     js::gc::State state() { return incrementalState; }
-    void recordNativeStackTop();
-    void notifyRequestEnd() { conservativeGC.updateForRequestEnd(); }
     bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
     void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
     void waitBackgroundSweepOrAllocEnd() { helperState.waitBackgroundSweepOrAllocEnd(); }
     void startBackgroundAllocationIfIdle() { helperState.startBackgroundAllocationIfIdle(); }
 
 #ifdef DEBUG
 
     bool onBackgroundThread() { return helperState.onBackgroundThread(); }
@@ -865,18 +825,16 @@ class GCRuntime
     GCHelperState helperState;
 
     /*
      * During incremental sweeping, this field temporarily holds the arenas of
      * the current AllocKind being swept in order of increasing free space.
      */
     SortedArenaList incrementalSweepList;
 
-    ConservativeGCData conservativeGC;
-
     friend class js::GCHelperState;
     friend class js::gc::MarkingValidator;
     friend class js::gc::AutoTraceSession;
 };
 
 #ifdef JS_GC_ZEAL
 inline int
 GCRuntime::zeal() {
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -129,37 +129,16 @@ MarkExactStackRoots(ThreadSafeContext* c
 static void
 MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
 {
     for (ContextIter cx(rt); !cx.done(); cx.next())
         MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx.get(), trc);
     MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
 }
 
-MOZ_NEVER_INLINE void
-ConservativeGCData::recordStackTop()
-{
-    /* Update the native stack pointer if it points to a bigger stack. */
-    uintptr_t dummy;
-    nativeStackTop = &dummy;
-
-    /*
-     * To record and update the register snapshot for the conservative scanning
-     * with the latest values we use setjmp.
-     */
-#if defined(_MSC_VER)
-# pragma warning(push)
-# pragma warning(disable: 4611)
-#endif
-    (void) setjmp(registerSnapshot.jmpbuf);
-#if defined(_MSC_VER)
-# pragma warning(pop)
-#endif
-}
-
 void
 JS::AutoIdArray::trace(JSTracer *trc)
 {
     MOZ_ASSERT(tag_ == IDARRAY);
     gc::MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
 }
 
 inline void
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -92,17 +92,17 @@ void
 StoreBuffer::MonoTypeBuffer<T>::handleOverflow(StoreBuffer *owner)
 {
     if (!owner->isAboutToOverflow()) {
         /*
          * Compact the buffer now, and if that fails to free enough space then
          * trigger a minor collection.
          */
         compact(owner);
-        if (isAboutToOverflow())
+        if (isLowOnSpace())
             owner->setAboutToOverflow();
     } else {
          /*
           * A minor GC has already been triggered, so there's no point
           * compacting unless the buffer is totally full.
           */
         if (storage_->availableInCurrentChunk() < sizeof(T))
             maybeCompact(owner);
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -73,17 +73,28 @@ static const size_t LifoAllocBlockSize =
  * The StoreBuffer observes all writes that occur in the system and performs
  * efficient filtering of them to derive a remembered set for nursery GC.
  */
 class StoreBuffer
 {
     friend class mozilla::ReentrancyGuard;
 
     /* The size at which a block is about to overflow. */
-    static const size_t MinAvailableSize = (size_t)(LifoAllocBlockSize * 1.0 / 8.0);
+    static const size_t LowAvailableThreshold = (size_t)(LifoAllocBlockSize * 1.0 / 16.0);
+
+    /*
+     * If the space available in the store buffer hits the
+     * LowAvailableThreshold and gets compacted, but still doesn't have at
+     * least HighAvailableThreshold space available, then we will trigger a
+     * minor GC. HighAvailableThreshold should be set to provide enough space
+     * for the mutator to run for a while in between compactions. (If
+     * HighAvailableThreshold is too low, we will thrash and spend most of the
+     * time compacting. If it is too high, we will tenure things too early.)
+     */
+    static const size_t HighAvailableThreshold = (size_t)(LifoAllocBlockSize * 1.0 / 4.0);
 
     /*
      * This buffer holds only a single type of edge. Using this buffer is more
      * efficient than the generic buffer when many writes will be to the same
      * type of edge: e.g. Value or Cell*.
      */
     template<typename T>
     struct MonoTypeBuffer
@@ -105,17 +116,21 @@ class StoreBuffer
             if (!storage_)
                 return;
 
             storage_->used() ? storage_->releaseAll() : storage_->freeAll();
             usedAtLastCompact_ = 0;
         }
 
         bool isAboutToOverflow() const {
-            return !storage_->isEmpty() && storage_->availableInCurrentChunk() < MinAvailableSize;
+            return !storage_->isEmpty() && storage_->availableInCurrentChunk() < LowAvailableThreshold;
+        }
+
+        bool isLowOnSpace() const {
+            return !storage_->isEmpty() && storage_->availableInCurrentChunk() < HighAvailableThreshold;
         }
 
         void handleOverflow(StoreBuffer *owner);
 
         /* Compaction algorithms. */
         void compactRemoveDuplicates(StoreBuffer *owner);
 
         /*
@@ -184,17 +199,17 @@ class StoreBuffer
         void clear() {
             if (!storage_)
                 return;
 
             storage_->used() ? storage_->releaseAll() : storage_->freeAll();
         }
 
         bool isAboutToOverflow() const {
-            return !storage_->isEmpty() && storage_->availableInCurrentChunk() < MinAvailableSize;
+            return !storage_->isEmpty() && storage_->availableInCurrentChunk() < LowAvailableThreshold;
         }
 
         /* Mark all generic edges. */
         void mark(StoreBuffer *owner, JSTracer *trc);
 
         template <typename T>
         void put(StoreBuffer *owner, const T &t) {
             MOZ_ASSERT(storage_);
--- a/js/src/jit-test/tests/asm.js/testBasic.js
+++ b/js/src/jit-test/tests/asm.js/testBasic.js
@@ -5,16 +5,17 @@ assertAsmTypeFail(USE_ASM);
 assertAsmTypeFail(USE_ASM + 'return');
 assertAsmTypeFail(USE_ASM + 'function f() 0');
 assertAsmTypeFail(USE_ASM + 'function f(){}');
 assertAsmTypeFail(USE_ASM + 'function f(){} return 0');
 assertAsmTypeFail(USE_ASM + 'function f() 0; return 0');
 assertAsmTypeFail(USE_ASM + 'function f(){} return g');
 assertAsmTypeFail(USE_ASM + 'function f(){} function f(){} return f');
 assertAsmTypeFail(USE_ASM + 'function f(){}; function g(){}; return {f, g}');
+assertAsmTypeFail(USE_ASM + 'var f = f;');
 assertAsmTypeFail(USE_ASM + 'var f=0; function f(){} return f');
 assertAsmTypeFail(USE_ASM + 'var f=glob.Math.imul; return {}');
 assertAsmTypeFail('glob', USE_ASM + 'var f=glob.Math.imul; function f(){} return f');
 assertAsmTypeFail('glob','foreign', USE_ASM + 'var f=foreign.foo; function f(){} return f');
 assertAsmTypeFail(USE_ASM + 'function f(){} var f=[f,f]; return f');
 assertAsmTypeFail(USE_ASM + 'function f() 0; return f');
 assertAsmTypeFail('"use strict";' + USE_ASM + 'function f() {} return f');
 assertAsmTypeFail(USE_ASM + '"use strict"; function f() {} return f');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1080991.js
@@ -0,0 +1,5 @@
+(function(){
+    for (var i = 0; i < 8; i++) {
+        var c = i
+    }
+})()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/test-scalar-replacement-float32.js
@@ -0,0 +1,98 @@
+setJitCompilerOption("ion.warmup.trigger", 30);
+var max = 40;
+
+// This test case verify that even if we do some scalar replacement, we keep a
+// correct computation of Float32 maths.  In this case, when the object is not
+// escaped, the "store" instruction are preventing any float32 optimization to
+// kick-in.  After Scalar Replacement, the store is removed, and the Float32
+// optimizations can avoid Double coercions.
+function escape_object(o) {
+    if (o.e) {
+        print(o);
+    }
+}
+
+var func = null;
+var check_object_argument_func = function (i, res) {
+    with ({}) { /* trun off the jit for this function, do not inline */ };
+    if (i == max - 1)
+        return funname.arguments[1].d;
+    return res;
+};
+
+var test_object_ref_check = eval(uneval(check_object_argument_func).replace("funname", "test_object_ref"));
+function test_object_ref(x, tmp) {
+    tmp = {
+        a: Math.fround(Math.pow(2 * x / max, 0)),
+        b: Math.fround(Math.pow(2 * x / max, 25)),
+        c: Math.fround(Math.pow(2 * x / max, 50)),
+        d: 0
+    };
+
+    tmp.d = tmp.a + tmp.b;
+    assertFloat32(tmp.d, false);
+    escape_object(tmp);
+    return test_object_ref_check(x, Math.fround(tmp.c + Math.fround(tmp.d)));
+}
+
+var test_object_check = eval(uneval(check_object_argument_func).replace("funname", "test_object"));
+function test_object(x, tmp) {
+    tmp = {
+        a: Math.fround(Math.pow(2 * x / max, 0)),
+        b: Math.fround(Math.pow(2 * x / max, 25)),
+        c: Math.fround(Math.pow(2 * x / max, 50)),
+        d: 0
+    };
+
+    tmp.d = tmp.a + tmp.b;
+    assertFloat32(tmp.d, false);
+    return test_object_check(x, Math.fround(tmp.c + Math.fround(tmp.d)));
+}
+
+// Same test with Arrays.
+function escape_array(o) {
+    if (o.length == 0) {
+        print(o);
+    }
+}
+
+var check_array_argument_func = function (i, res) {
+    with ({}) { /* trun off the jit for this function, do not inline */ };
+    if (i == max - 1) {
+        return funname.arguments[1][3];
+    }
+    return res;
+};
+
+var test_array_ref_check = eval(uneval(check_array_argument_func).replace("funname", "test_array_ref"));
+function test_array_ref(x, tmp) {
+    tmp = [
+        Math.fround(Math.pow(2 * x / max, 0)),
+        Math.fround(Math.pow(2 * x / max, 25)),
+        Math.fround(Math.pow(2 * x / max, 50)),
+        0
+    ];
+    tmp[3] = tmp[0] + tmp[1];
+    assertFloat32(tmp[3], false);
+    escape_array(tmp);
+    return test_array_ref_check(x, Math.fround(tmp[2] + Math.fround(tmp[3])));
+}
+
+var test_array_check = eval(uneval(check_array_argument_func).replace("funname", "test_array"));
+function test_array(x, tmp) {
+    tmp = [
+        Math.fround(Math.pow(2 * x / max, 0)),
+        Math.fround(Math.pow(2 * x / max, 25)),
+        Math.fround(Math.pow(2 * x / max, 50)),
+        0
+    ];
+    tmp[3] = tmp[0] + tmp[1];
+    assertFloat32(tmp[3], false);
+    return test_array_check(x, Math.fround(tmp[2] + Math.fround(tmp[3])));
+}
+
+
+for (var i = 0; i < max; i++) {
+    assertEq(test_object_ref(i, undefined), test_object(i, undefined));
+    assertEq(test_array_ref(i, undefined), test_array(i, undefined));
+}
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -402,18 +402,17 @@ EliminateTriviallyDeadResumePointOperand
 
     size_t top = rp->stackDepth() - 1;
     MOZ_ASSERT(!rp->isObservableOperand(top));
 
     MDefinition *def = rp->getOperand(top);
     if (def->isConstant())
         return;
 
-    MConstant *constant = MConstant::New(graph.alloc(), MagicValue(JS_OPTIMIZED_OUT));
-    rp->block()->insertBefore(*(rp->block()->begin()), constant);
+    MConstant *constant = rp->block()->optimizedOutConstant(graph.alloc());
     rp->replaceOperand(top, constant);
 }
 
 // Operands to a resume point which are dead at the point of the resume can be
 // replaced with a magic value. This analysis supports limited detection of
 // dead operands, pruning those which are defined in the resume point's basic
 // block and have no uses outside the block or at points later than the resume
 // point.
@@ -717,18 +716,20 @@ jit::EliminatePhis(MIRGenerator *mir, MI
         }
     }
 
     // Sweep dead phis.
     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
         MPhiIterator iter = block->phisBegin();
         while (iter != block->phisEnd()) {
             MPhi *phi = *iter++;
-            if (phi->isUnused())
+            if (phi->isUnused()) {
+                phi->optimizeOutAllUses(graph.alloc());
                 block->discardPhi(phi);
+            }
         }
     }
 
     return true;
 }
 
 namespace {
 
@@ -1759,19 +1760,17 @@ CheckPredecessorImpliesSuccessor(MBasicB
             return true;
     }
     return false;
 }
 
 static bool
 CheckOperandImpliesUse(MNode *n, MDefinition *operand)
 {
-    // TODO: Fix code that leaves discarded things in resume point operands
-    // (bug 1055690).
-    MOZ_ASSERT_IF(!n->isResumePoint(), !operand->isDiscarded());
+    MOZ_ASSERT(!operand->isDiscarded());
     MOZ_ASSERT(operand->block() != nullptr);
 
     for (MUseIterator i = operand->usesBegin(); i != operand->usesEnd(); i++) {
         if (i->consumer() == n)
             return true;
     }
     return false;
 }
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -59,17 +59,17 @@ JitOptions::JitOptions()
     SET_DEFAULT(checkOsiPointRegisters, false);
 #endif
 
     // Whether to enable extra code to perform dynamic validation of
     // RangeAnalysis results.
     SET_DEFAULT(checkRangeAnalysis, false);
 
     // Toggle whether eager scalar replacement is globally disabled.
-    SET_DEFAULT(disableScalarReplacement, true); // experimental
+    SET_DEFAULT(disableScalarReplacement, false);
 
     // Toggle whether global value numbering is globally disabled.
     SET_DEFAULT(disableGvn, false);
 
     // Toggles whether loop invariant code motion is globally disabled.
     SET_DEFAULT(disableLicm, false);
 
     // Toggles whether inlining is globally disabled.
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -538,16 +538,32 @@ MDefinition::justReplaceAllUsesWith(MDef
     MOZ_ASSERT(dom != nullptr);
     MOZ_ASSERT(dom != this);
 
     for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i)
         i->setProducerUnchecked(dom);
     dom->uses_.takeElements(uses_);
 }
 
+void
+MDefinition::optimizeOutAllUses(TempAllocator &alloc)
+{
+    for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
+        MUse *use = *i++;
+        MConstant *constant = use->consumer()->block()->optimizedOutConstant(alloc);
+
+        // Update the resume point operand to use the optimized-out constant.
+        use->setProducerUnchecked(constant);
+        constant->addUseUnchecked(use);
+    }
+
+    // Remove dangling pointers.
+    this->uses_.clear();
+}
+
 bool
 MDefinition::emptyResultTypeSet() const
 {
     return resultTypeSet() && resultTypeSet()->empty();
 }
 
 MConstant *
 MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintList *constraints)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -674,21 +674,29 @@ class MDefinition : public MNode
     void addUseUnchecked(MUse *use) {
         MOZ_ASSERT(use->producer() == this);
         uses_.pushFrontUnchecked(use);
     }
     void replaceUse(MUse *old, MUse *now) {
         MOZ_ASSERT(now->producer() == this);
         uses_.replace(old, now);
     }
+
+    // Replace the current instruction by a dominating instruction |dom| in all
+    // uses of the current instruction.
     void replaceAllUsesWith(MDefinition *dom);
 
     // Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands.
     void justReplaceAllUsesWith(MDefinition *dom);
 
+    // Replace the current instruction by an optimized-out constant in all uses
+    // of the current instruction. Note, that optimized-out constant should not
+    // be observed, and thus they should not flow in any computation.
+    void optimizeOutAllUses(TempAllocator &alloc);
+
     // Mark this instruction as having replaced all uses of ins, as during GVN,
     // returning false if the replacement should not be performed. For use when
     // GVN eliminates instructions which are not equivalent to one another.
     virtual bool updateForReplacement(MDefinition *ins) {
         return true;
     }
 
     void setVirtualRegister(uint32_t vreg) {
@@ -2655,17 +2663,19 @@ class MNewDerivedTypedObject
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
         return true;
     }
 };
 
 // Represent the content of all slots of an object.  This instruction is not
 // lowered and is not used to generate code.
-class MObjectState : public MVariadicInstruction
+class MObjectState
+  : public MVariadicInstruction,
+    public NoFloatPolicyAfter<1>::Data
 {
   private:
     uint32_t numSlots_;
     uint32_t numFixedSlots_;
 
     explicit MObjectState(MDefinition *obj);
 
     bool init(TempAllocator &alloc, MDefinition *obj);
@@ -2717,17 +2727,19 @@ class MObjectState : public MVariadicIns
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
         return true;
     }
 };
 
 // Represent the contents of all elements of an array.  This instruction is not
 // lowered and is not used to generate code.
-class MArrayState : public MVariadicInstruction
+class MArrayState
+  : public MVariadicInstruction,
+    public NoFloatPolicyAfter<2>::Data
 {
   private:
     uint32_t numElements_;
 
     explicit MArrayState(MDefinition *arr)
     {
         // This instruction is only used as a summary for bailout paths.
         setResultType(MIRType_Object);
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -747,16 +747,30 @@ MBasicBlock::peek(int32_t depth)
 }
 
 void
 MBasicBlock::discardLastIns()
 {
     discard(lastIns());
 }
 
+MConstant *
+MBasicBlock::optimizedOutConstant(TempAllocator &alloc)
+{
+    // If the first instruction is a MConstant(MagicValue(JS_OPTIMIZED_OUT))
+    // then reuse it.
+    MInstruction *ins = *begin();
+    if (ins->type() == MIRType_MagicOptimizedOut)
+        return ins->toConstant();
+
+    MConstant *constant = MConstant::New(alloc, MagicValue(JS_OPTIMIZED_OUT));
+    insertBefore(ins, constant);
+    return constant;
+}
+
 void
 MBasicBlock::addFromElsewhere(MInstruction *ins)
 {
     MOZ_ASSERT(ins->block() != this);
 
     // Remove |ins| from its containing block.
     ins->block()->instructions_.remove(ins);
 
--- a/js/src/jit/MIRGraph.h
+++ b/js/src/jit/MIRGraph.h
@@ -362,16 +362,18 @@ class MBasicBlock : public TempObject, p
     }
     bool hasLastIns() const {
         return !instructions_.empty() && instructions_.rbegin()->isControlInstruction();
     }
     MControlInstruction *lastIns() const {
         MOZ_ASSERT(hasLastIns());
         return instructions_.rbegin()->toControlInstruction();
     }
+    // Find or allocate an optimized out constant.
+    MConstant *optimizedOutConstant(TempAllocator &alloc);
     MPhiIterator phisBegin() const {
         return phis_.begin();
     }
     MPhiIterator phisBegin(MPhi *at) const {
         return phis_.begin(at);
     }
     MPhiIterator phisEnd() const {
         return phis_.end();
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -451,19 +451,18 @@ ParallelSafetyVisitor::convertToBailout(
     // We expect iter to be settled on the unsafe instruction.
     MInstruction *ins = *iter;
     MBasicBlock *block = ins->block();
     MOZ_ASSERT(unsafe()); // `block` must have contained unsafe items
     MOZ_ASSERT(block->isMarked()); // `block` must have been reachable to get here
 
     clearUnsafe();
 
-    // Allocate a new bailout instruction and transplant the resume point.
+    // Allocate a new bailout instruction.
     MBail *bail = MBail::New(graph_.alloc(), Bailout_ParallelUnsafe);
-    TransplantResumePoint(ins, bail);
 
     // Discard the rest of the block and sever its link to its successors in
     // the CFG.
     for (size_t i = 0; i < block->numSuccessors(); i++)
         block->getSuccessor(i)->removePredecessor(block);
     block->discardAllInstructionsStartingAt(iter);
 
     // End the block in a bail.
@@ -777,17 +776,16 @@ ParallelSafetyVisitor::visitSpecializedI
 // Throw
 
 bool
 ParallelSafetyVisitor::visitThrow(MThrow *thr)
 {
     MBasicBlock *block = thr->block();
     MOZ_ASSERT(block->lastIns() == thr);
     MBail *bail = MBail::New(alloc(), Bailout_ParallelUnsafe);
-    TransplantResumePoint(thr, bail);
     block->discardLastIns();
     block->add(bail);
     block->end(MUnreachable::New(alloc()));
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Callee extraction
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -499,16 +499,28 @@ NoFloatPolicy<Op>::staticAdjustInputs(Te
     return true;
 }
 
 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
 
+template <unsigned FirstOp>
+bool
+NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator &alloc, MInstruction *def)
+{
+    for (size_t op = FirstOp, e = def->numOperands(); op < e; op++)
+        EnsureOperandNotFloat32(alloc, def, op);
+    return true;
+}
+
+template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator &alloc, MInstruction *def);
+template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator &alloc, MInstruction *def);
+
 template <unsigned Op>
 bool
 BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MDefinition *in = ins->getOperand(Op);
     if (in->type() == MIRType_Value)
         return true;
 
@@ -951,16 +963,18 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >)                    \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >)                    \
     _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >)                     \
     _(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >)                     \
     _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >)            \
     _(MixPolicy<StringPolicy<0>, IntPolicy<1> >)                        \
     _(MixPolicy<StringPolicy<0>, StringPolicy<1> >)                     \
     _(NoFloatPolicy<0>)                                                 \
+    _(NoFloatPolicyAfter<1>)                                            \
+    _(NoFloatPolicyAfter<2>)                                            \
     _(ObjectPolicy<0>)                                                  \
     _(ObjectPolicy<1>)                                                  \
     _(ObjectPolicy<3>)                                                  \
     _(StringPolicy<0>)
 
 
 namespace js {
 namespace jit {
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -228,16 +228,26 @@ class NoFloatPolicy : public TypePolicy
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
     }
 };
 
+// Policy for guarding variadic instructions such as object / array state
+// instructions.
+template <unsigned FirstOp>
+class NoFloatPolicyAfter : public TypePolicy
+{
+  public:
+    EMPTY_DATA_;
+    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+};
+
 // Box objects or strings as an input to a ToDouble instruction.
 class ToDoublePolicy : public BoxInputsPolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
         return staticAdjustInputs(alloc, def);
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -299,20 +299,16 @@ ValueNumberer::discardDefsRecursively(MD
 // becomes unused, so it isn't trivial to do.
 bool
 ValueNumberer::releaseResumePointOperands(MResumePoint *resume)
 {
     for (size_t i = 0, e = resume->numOperands(); i < e; ++i) {
         if (!resume->hasOperand(i))
             continue;
         MDefinition *op = resume->getOperand(i);
-        // TODO: We shouldn't leave discarded operands sitting around
-        // (bug 1055690).
-        if (op->isDiscarded())
-            continue;
         resume->releaseOperand(i);
 
         // We set the UseRemoved flag when removing resume point operands,
         // because even though we may think we're certain that a particular
         // branch might not be taken, the type information might be incomplete.
         if (!handleUseReleased(op, SetUseRemoved))
             return false;
     }
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -3236,21 +3236,53 @@ Simulator::decodeType6(SimInstruction *i
     decodeType6CoprocessorIns(instr);
 }
 
 void
 Simulator::decodeType7(SimInstruction *instr)
 {
     if (instr->bit(24) == 1)
         softwareInterrupt(instr);
+    else if (instr->bit(4) == 1 && instr->bits(11,9) != 5)
+        decodeType7CoprocessorIns(instr);
     else
         decodeTypeVFP(instr);
 }
 
 void
+Simulator::decodeType7CoprocessorIns(SimInstruction *instr)
+{
+    if (instr->bit(20) == 0) {
+        // MCR, MCR2
+        if (instr->coprocessorValue() == 15) {
+            int opc1 = instr->bits(23,21);
+            int opc2 = instr->bits(7,5);
+            int CRn = instr->bits(19,16);
+            int CRm = instr->bits(3,0);
+            if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 10) {
+                // ARMv6 DSB instruction - do nothing now, see comments above
+            } else if (opc1 == 0 && opc2 == 5 && CRn == 7 && CRm == 10) {
+                // ARMv6 DMB instruction - do nothing now, see comments above
+            }
+            else if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 5) {
+                // ARMv6 ISB instruction - do nothing now, see comments above
+            }
+            else {
+                MOZ_CRASH();
+            }
+        } else {
+            MOZ_CRASH();
+        }
+    } else {
+        // MRC, MRC2
+        MOZ_CRASH();
+    }
+}
+
+void
 Simulator::decodeTypeVFP(SimInstruction *instr)
 {
     MOZ_ASSERT(instr->typeValue() == 7 && instr->bit(24) == 0);
     MOZ_ASSERT(instr->bits(11, 9) == 0x5);
 
     // Obtain double precision register codes.
     VFPRegPrecision precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
     int vm = instr->VFPMRegValue(precision);
@@ -4072,16 +4104,25 @@ Simulator::decodeSpecialCondition(SimIns
         break;
       case 0xB:
         if (instr->bits(22, 20) == 5 && instr->bits(15, 12) == 0xf) {
             // pld: ignore instruction.
         } else {
             MOZ_CRASH();
         }
         break;
+      case 0x1C:
+      case 0x1D:
+        if (instr->bit(4) == 1 && instr->bits(11,9) != 5) {
+            // MCR, MCR2, MRC, MRC2 with cond == 15
+            decodeType7CoprocessorIns(instr);
+        } else {
+            MOZ_CRASH();
+        }
+        break;
       default:
         MOZ_CRASH();
     }
 }
 
 // Executes the current instruction.
 void
 Simulator::instructionDecode(SimInstruction *instr)
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -259,16 +259,19 @@ class Simulator
     void decodeSpecialCondition(SimInstruction *instr);
 
     void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction *instr);
     void decodeVCMP(SimInstruction *instr);
     void decodeVCVTBetweenDoubleAndSingle(SimInstruction *instr);
     void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction *instr);
     void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction *instr);
 
+    // Support for some system functions.
+    void decodeType7CoprocessorIns(SimInstruction *instr);
+
     // Executes one instruction.
     void instructionDecode(SimInstruction *instr);
 
   public:
     static bool ICacheCheckingEnabled;
     static void FlushICache(void *start, size_t size);
 
     static int64_t StopSimAt;
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -6,16 +6,17 @@
 
 Program('jsapi-tests')
 
 UNIFIED_SOURCES += [
     'selfTest.cpp',
     'testAddPropertyPropcache.cpp',
     'testArgumentsObject.cpp',
     'testArrayBuffer.cpp',
+    'testArrayBufferView.cpp',
     'testBindCallable.cpp',
     'testBug604087.cpp',
     'testCallNonGenericMethodOnProxy.cpp',
     'testChromeBuffer.cpp',
     'testClassGetter.cpp',
     'testCloneScript.cpp',
     'testContexts.cpp',
     'testCustomIterator.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testArrayBufferView.cpp
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+
+#include "jsfriendapi.h"
+
+#include "jsapi-tests/tests.h"
+
+BEGIN_TEST(testArrayBufferView_type)
+{
+    CHECK((TestViewType<uint8_t,
+                        Create<JS_NewUint8Array, 7>,
+                        JS_GetObjectAsUint8Array,
+                        js::Scalar::Uint8,
+                        7, 7>(cx)));
+
+    CHECK((TestViewType<int8_t,
+                        Create<JS_NewInt8Array, 33>,
+                        JS_GetObjectAsInt8Array,
+                        js::Scalar::Int8,
+                        33, 33>(cx)));
+
+    CHECK((TestViewType<uint8_t,
+                        Create<JS_NewUint8ClampedArray, 7>,
+                        JS_GetObjectAsUint8ClampedArray,
+                        js::Scalar::Uint8Clamped,
+                        7, 7>(cx)));
+
+    CHECK((TestViewType<uint16_t,
+                        Create<JS_NewUint16Array, 3>,
+                        JS_GetObjectAsUint16Array,
+                        js::Scalar::Uint16,
+                        3, 6>(cx)));
+
+    CHECK((TestViewType<int16_t,
+                        Create<JS_NewInt16Array, 17>,
+                        JS_GetObjectAsInt16Array,
+                        js::Scalar::Int16,
+                        17, 34>(cx)));
+
+    CHECK((TestViewType<uint32_t,
+                        Create<JS_NewUint32Array, 15>,
+                        JS_GetObjectAsUint32Array,
+                        js::Scalar::Uint32,
+                        15, 60>(cx)));
+
+    CHECK((TestViewType<int32_t,
+                        Create<JS_NewInt32Array, 8>,
+                        JS_GetObjectAsInt32Array,
+                        js::Scalar::Int32,
+                        8, 32>(cx)));
+
+    CHECK((TestViewType<float,
+                        Create<JS_NewFloat32Array, 7>,
+                        JS_GetObjectAsFloat32Array,
+                        js::Scalar::Float32,
+                        7, 28>(cx)));
+
+    CHECK((TestViewType<double,
+                        Create<JS_NewFloat64Array, 9>,
+                        JS_GetObjectAsFloat64Array,
+                        js::Scalar::Float64,
+                        9, 72>(cx)));
+
+    CHECK((TestViewType<uint8_t,
+                        CreateDataView,
+                        JS_GetObjectAsArrayBufferView,
+                        js::Scalar::TypeMax,
+                        8, 8>(cx)));
+
+    JS::Rooted<JS::Value> hasTypedObject(cx);
+    EVAL("typeof TypedObject !== 'undefined'", &hasTypedObject);
+    if (hasTypedObject.isTrue()) {
+        JS::Rooted<JS::Value> tval(cx);
+        EVAL("var T = new TypedObject.StructType({ x: TypedObject.uint32 });\n"
+             "new T(new ArrayBuffer(4));",
+             &tval);
+
+        JS::Rooted<JSObject*> tobj(cx, &tval.toObject());
+        CHECK(!JS_IsArrayBufferViewObject(tobj));
+    }
+
+    return true;
+}
+
+static JSObject *
+CreateDataView(JSContext *cx)
+{
+    JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
+    if (!global)
+        return nullptr;
+
+    static const char code[] = "new DataView(new ArrayBuffer(8))";
+
+    JS::Rooted<JS::Value> val(cx);
+    if (!JS_EvaluateScript(cx, global, code, strlen(code), __FILE__, __LINE__, &val))
+        return nullptr;
+
+    JS::Rooted<JSObject*> dv(cx, &val.toObject());
+    if (!JS_IsDataViewObject(dv))
+        return nullptr;
+
+    return dv;
+}
+
+template<JSObject * CreateTypedArray(JSContext *cx, uint32_t length),
+         size_t Length>
+static JSObject *
+Create(JSContext *cx)
+{
+    return CreateTypedArray(cx, Length);
+}
+
+template<typename T,
+         JSObject * CreateViewType(JSContext *cx),
+         JSObject * GetObjectAs(JSObject *obj, uint32_t *length, T **data),
+         js::Scalar::Type ExpectedType,
+         uint32_t ExpectedLength,
+         uint32_t ExpectedByteLength>
+bool TestViewType(JSContext *cx)
+{
+    JS::Rooted<JSObject*> obj(cx, CreateViewType(cx));
+    CHECK(obj);
+
+    CHECK(JS_IsArrayBufferViewObject(obj));
+
+    CHECK(JS_GetArrayBufferViewType(obj) == ExpectedType);
+
+    CHECK(JS_GetArrayBufferViewByteLength(obj) == ExpectedByteLength);
+
+    {
+        JS::AutoCheckCannotGC nogc;
+        T *data1 = static_cast<T*>(JS_GetArrayBufferViewData(obj, nogc));
+
+        T *data2;
+        uint32_t len;
+        CHECK(obj == GetObjectAs(obj, &len, &data2));
+        CHECK(data1 == data2);
+        CHECK(len == ExpectedLength);
+    }
+
+    return true;
+}
+
+END_TEST(testArrayBufferView_type)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -692,17 +692,16 @@ StopRequest(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime();
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
     MOZ_ASSERT(rt->requestDepth != 0);
     if (rt->requestDepth != 1) {
         rt->requestDepth--;
     } else {
-        rt->gc.notifyRequestEnd();
         rt->requestDepth = 0;
         rt->triggerActivityCallback(false);
     }
 }
 
 JS_PUBLIC_API(void)
 JS_BeginRequest(JSContext *cx)
 {
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -157,17 +157,17 @@ assertSameCompartment(ThreadSafeContext 
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
 #endif
 }
 
 template <class T1> inline void
 assertSameCompartmentDebugOnly(ThreadSafeContext *cx, const T1 &t1)
 {
-#ifdef DEBUG
+#if defined(DEBUG) && defined(JS_CRASH_DIAGNOSTICS)
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
 #endif
 }
 
 template <class T1, class T2> inline void
 assertSameCompartment(ThreadSafeContext *cx, const T1 &t1, const T2 &t2)
 {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1343,25 +1343,16 @@ GCRuntime::init(uint32_t maxbytes, uint3
 
     if (!marker.init(mode))
         return false;
 
     return true;
 }
 
 void
-GCRuntime::recordNativeStackTop()
-{
-    /* Record the stack top here only if we are called from a request. */
-    if (!rt->requestDepth)
-        return;
-    conservativeGC.recordStackTop();
-}
-
-void
 GCRuntime::finish()
 {
     /*
      * Wait until the background finalization stops and the helper thread
      * shuts down before we forcefully release any remaining GC memory.
      */
     helperState.finish();
 
@@ -5806,18 +5797,16 @@ GCRuntime::collect(bool incremental, int
         return;
 #endif
 
     MOZ_ASSERT_IF(!incremental || budget != SliceBudget::Unlimited, JSGC_INCREMENTAL);
 
     AutoStopVerifyingBarriers av(rt, reason == JS::gcreason::SHUTDOWN_CC ||
                                      reason == JS::gcreason::DESTROY_RUNTIME);
 
-    recordNativeStackTop();
-
     gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), reason);
 
     cleanUpEverything = ShouldCleanUpEverything(reason, gckind);
 
     bool repeat = false;
     do {
         /*
          * Let the API user decide to defer a GC if it wants to (unless this
@@ -6058,17 +6047,16 @@ AutoFinishGC::AutoFinishGC(JSRuntime *rt
     rt->gc.waitBackgroundSweepEnd();
 }
 
 AutoPrepareForTracing::AutoPrepareForTracing(JSRuntime *rt, ZoneSelector selector)
   : finish(rt),
     session(rt),
     copy(rt, selector)
 {
-    rt->gc.recordNativeStackTop();
 }
 
 JSCompartment *
 js::NewCompartment(JSContext *cx, Zone *zone, JSPrincipals *principals,
                    const JS::CompartmentOptions &options)
 {
     JSRuntime *rt = cx->runtime();
     JS_AbortIfWrongThread(rt);
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -356,16 +356,19 @@ void
 ShapeGetterSetterRef::mark(JSTracer *trc)
 {
     // Update the current shape's entry in the parent KidsHash table if needed.
     // This is necessary as the computed hash includes the getter/setter
     // pointers.
 
     JSObject *obj = *objp;
     JSObject *prior = obj;
+    if (!prior)
+        return;
+
     trc->setTracingLocation(&*prior);
     gc::Mark(trc, &obj, "AccessorShape getter or setter");
     if (obj == *objp)
         return;
 
     Shape *parent = shape->parent;
     if (shape->inDictionary() || !parent->kids.isHash()) {
         *objp = obj;
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -288,17 +288,17 @@ Poison(void *ptr, int value, size_t num)
 
     if (poison)
         return memset(ptr, value, num);
 
     return nullptr;
 }
 
 /* Crash diagnostics */
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(MOZ_ASAN)
 # define JS_CRASH_DIAGNOSTICS 1
 #endif
 #if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL)
 # define JS_POISON(p, val, size) Poison(p, val, size)
 #else
 # define JS_POISON(p, val, size) ((void) 0)
 #endif
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5935,17 +5935,17 @@ main(int argc, char **argv, char **envp)
                                          "shell's global")
         || !op.addIntOption('\0', "thread-count", "COUNT", "Use COUNT auxiliary threads "
                             "(default: # of cores - 1)", -1)
         || !op.addBoolOption('\0', "ion", "Enable IonMonkey (default)")
         || !op.addBoolOption('\0', "no-ion", "Disable IonMonkey")
         || !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
         || !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
         || !op.addStringOption('\0', "ion-scalar-replacement", "on/off",
-                               "Scalar Replacement (default: off, on to enable)")
+                               "Scalar Replacement (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-gvn", "[mode]",
                                "Specify Ion global value numbering:\n"
                                "  off: disable GVN\n"
                                "  on:  enable GVN (default)\n")
         || !op.addStringOption('\0', "ion-licm", "on/off",
                                "Loop invariant code motion (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
                                "Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Object/clear-dictionary-accessor-getset.js
@@ -0,0 +1,55 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var gTestfile = "clear-dictionary-accessor-getset.js";
+var BUGNUMBER = 1082662;
+var summary =
+  "Properly handle GC of a dictionary accessor property whose [[Get]] or " +
+  "[[Set]] has been changed to |undefined|";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+function test(field)
+{
+  var prop = "[[" + field[0].toUpperCase() + field.substring(1) + "]]";
+  print("Testing for GC crashes after setting " + prop + " to undefined...");
+
+  function inner()
+  {
+     // Create an object with an accessor property.
+     var obj = { x: 42, get y() {}, set y(v) {} };
+
+     // 1) convert it to dictionary mode, in the process 2) creating a new
+     // version of that accessor property whose [[Get]] and [[Set]] are objects
+     // that trigger post barriers.
+     delete obj.x;
+
+     var desc = {};
+     desc[field] = undefined;
+
+     // Overwrite [[field]] with undefined.  Note #1 above is necessary so this
+     // is an actual *overwrite*, and not (possibly) a shape-tree fork that
+     // doesn't overwrite.
+     Object.defineProperty(obj, "y", desc);
+
+  }
+
+  inner();
+  gc(); // In unfixed code, this crashes trying to mark a null [[field]].
+}
+
+test("get");
+test("set");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -776,33 +776,34 @@ ArrayBufferObject::objectMoved(JSObject 
     if (src.hasInlineData())
         dst.setSlot(DATA_SLOT, PrivateValue(dst.inlineDataPointer()));
 }
 
 ArrayBufferViewObject *
 ArrayBufferObject::firstView()
 {
     return getSlot(FIRST_VIEW_SLOT).isObject()
-           ? &getSlot(FIRST_VIEW_SLOT).toObject().as<ArrayBufferViewObject>()
-           : nullptr;
+        ? static_cast<ArrayBufferViewObject*>(&getSlot(FIRST_VIEW_SLOT).toObject())
+        : nullptr;
 }
 
 void
 ArrayBufferObject::setFirstView(ArrayBufferViewObject *view)
 {
     setSlot(FIRST_VIEW_SLOT, ObjectOrNullValue(view));
 }
 
 bool
 ArrayBufferObject::addView(JSContext *cx, JSObject *viewArg)
 {
     // Note: we don't pass in an ArrayBufferViewObject as the argument due to
     // tricky inheritance in the various view classes. View classes do not
     // inherit from ArrayBufferViewObject so won't be upcast automatically.
-    ArrayBufferViewObject *view = &viewArg->as<ArrayBufferViewObject>();
+    MOZ_ASSERT(viewArg->is<ArrayBufferViewObject>() || viewArg->is<TypedObject>());
+    ArrayBufferViewObject *view = static_cast<ArrayBufferViewObject*>(viewArg);
 
     if (!firstView()) {
         setFirstView(view);
         return true;
     }
     return cx->compartment()->innerViews.addView(cx, this, view);
 }
 
@@ -980,17 +981,17 @@ ArrayBufferViewObject::trace(JSTracer *t
         obj->initPrivate(buf.dataPointer() + offset);
     }
 }
 
 template <>
 bool
 JSObject::is<js::ArrayBufferViewObject>() const
 {
-    return is<DataViewObject>() || is<TypedArrayObject>() || is<TypedObject>();
+    return is<DataViewObject>() || is<TypedArrayObject>();
 }
 
 void
 ArrayBufferViewObject::neuter(void *newData)
 {
     MOZ_ASSERT(newData != nullptr);
     if (is<DataViewObject>())
         as<DataViewObject>().neuter(newData);
@@ -1206,17 +1207,19 @@ JS_GetArrayBufferViewData(JSObject *obj,
 }
 
 JS_FRIEND_API(JSObject *)
 JS_GetArrayBufferViewBuffer(JSContext *cx, HandleObject objArg)
 {
     JSObject *obj = CheckedUnwrap(objArg);
     if (!obj)
         return nullptr;
-    Rooted<ArrayBufferViewObject *> viewObject(cx, &obj->as<ArrayBufferViewObject>());
+    MOZ_ASSERT(obj->is<ArrayBufferViewObject>());
+
+    Rooted<ArrayBufferViewObject *> viewObject(cx, static_cast<ArrayBufferViewObject*>(obj));
     return ArrayBufferViewObject::bufferObject(cx, viewObject);
 }
 
 JS_FRIEND_API(uint32_t)
 JS_GetArrayBufferViewByteLength(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1236,17 +1236,18 @@ OptionsBase::ParseString(const char *nam
 
     if (!value.isString()) {
         JS_ReportError(mCx, "Expected a string value for property %s", name);
         return false;
     }
 
     char *tmp = JS_EncodeString(mCx, value.toString());
     NS_ENSURE_TRUE(tmp, false);
-    prop.Adopt(tmp, strlen(tmp));
+    prop.Assign(tmp, strlen(tmp));
+    js_free(tmp);
     return true;
 }
 
 /*
  * Helper that tries to get a string property from the options object.
  */
 bool
 OptionsBase::ParseString(const char *name, nsString &prop)
--- a/js/xpconnect/src/XPCDebug.cpp
+++ b/js/xpconnect/src/XPCDebug.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* 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 "xpcprivate.h"
 #include "jsprf.h"
+#include "nsThreadUtils.h"
+#include "nsContentUtils.h"
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 static void DebugDump(const char* fmt, ...)
 {
   char buffer[2048];
@@ -27,19 +29,22 @@ static void DebugDump(const char* fmt, .
   if (IsDebuggerPresent()) {
     OutputDebugStringA(buffer);
   }
 #endif
   printf("%s", buffer);
 }
 
 bool
-xpc_DumpJSStack(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps)
+xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps)
 {
-    if (char* buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) {
+    JSContext* cx = nsContentUtils::GetCurrentJSContextForThread();
+    if (!cx) {
+        printf("there is no JSContext on the stack!\n");
+    } else if (char* buf = xpc_PrintJSStack(cx, showArgs, showLocals, showThisProps)) {
         DebugDump("%s\n", buf);
         JS_smprintf_free(buf);
     }
     return true;
 }
 
 char*
 xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -26,24 +26,16 @@ members = [
     #   - nsIDOMJSWindow.{prompt,setTimeout,setInterval,open,openDialog}
     #
     # (And nsIDOMModalContentWindow.returnValue is an attribute of type
     # nsIVariant, which qsgen.py can't handle.)
 
     # dom/interfaces/xpath
     'nsIDOMXPathNSResolver.lookupNamespaceURI',
 
-    # layout/xul/base/public
-    'nsIBoxObject.x',
-    'nsIBoxObject.y',
-    'nsIBoxObject.screenX',
-    'nsIBoxObject.screenY',
-    'nsIBoxObject.width',
-    'nsIBoxObject.height',
-
     ]
 
 # Most interfaces can be found by searching the includePath; to find
 # nsIDOMEvent, for example, just look for nsIDOMEvent.idl.  But IDL filenames
 # for very long interface names are slightly abbreviated, and many interfaces
 # don't have their own files, just for extra wackiness.  So qsgen.py needs
 # a little help.
 #
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -963,21 +963,17 @@ nsXPConnect::DebugDumpObject(nsISupports
 }
 
 /* void debugDumpJSStack (in bool showArgs, in bool showLocals, in bool showThisProps); */
 NS_IMETHODIMP
 nsXPConnect::DebugDumpJSStack(bool showArgs,
                               bool showLocals,
                               bool showThisProps)
 {
-    JSContext* cx = GetCurrentJSContext();
-    if (!cx)
-        printf("there is no JSContext on the nsIThreadJSContextStack!\n");
-    else
-        xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps);
+    xpc_DumpJSStack(showArgs, showLocals, showThisProps);
 
     return NS_OK;
 }
 
 char*
 nsXPConnect::DebugPrintJSStack(bool showArgs,
                                bool showLocals,
                                bool showThisProps)
@@ -1384,22 +1380,17 @@ nsXPConnect::ReadFunction(nsIObjectInput
 {
     return ReadScriptOrFunction(stream, cx, nullptr, functionObjp);
 }
 
 /* These are here to be callable from a debugger */
 extern "C" {
 JS_EXPORT_API(void) DumpJSStack()
 {
-    nsresult rv;
-    nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
-    if (NS_SUCCEEDED(rv) && xpc)
-        xpc->DebugDumpJSStack(true, true, false);
-    else
-        printf("failed to get XPConnect service!\n");
+    xpc_DumpJSStack(true, true, false);
 }
 
 JS_EXPORT_API(char*) PrintJSStack()
 {
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     return (NS_SUCCEEDED(rv) && xpc) ?
         xpc->DebugPrintJSStack(true, true, false) :
--- a/js/xpconnect/src/qsgen.py
+++ b/js/xpconnect/src/qsgen.py
@@ -1093,20 +1093,17 @@ def writeSpecs(f, elementType, varname, 
     f.write("};\n\n")
 
 def writeDefiner(f, conf, stringtable, interfaces):
     f.write("// === Definer\n\n")
 
     # Write out the properties and functions
     propspecs_indices = {}
     funcspecs_indices = {}
-    prop_array_name = "all_properties"
     func_array_name = "all_functions"
-    writeSpecs(f, "xpc_qsPropertySpec", prop_array_name,
-               "propspecs", propspecs_indices, interfaces)
     writeSpecs(f, "xpc_qsFunctionSpec", func_array_name,
                "funcspecs", funcspecs_indices, interfaces)
 
     # generate the static hash table
     loadFactor = 0.6
     size = int(len(interfaces) / loadFactor)
     buckets = [[] for i in range(size)]
     for iface in interfaces:
@@ -1142,16 +1139,17 @@ def writeDefiner(f, conf, stringtable, i
                      % (m3[0:2], m3[2:4], m4[0:2], m4[2:4],
                         m4[4:6], m4[6:8], m4[8:10], m4[10:12]))
             iid = ('{0x%s, 0x%s, 0x%s, %s}' % (m0, m1, m2, m3arr))
 
             # properties fields
             prop_index = 0
             prop_n_entries = 0
             if iface.propspecs:
+                assert False
                 prop_index = propspecs_indices[iface.name]
                 prop_n_entries = len(iface.propspecs)
 
             # member fields
             func_index = 0
             func_n_entries = 0
             if iface.funcspecs:
                 func_index = funcspecs_indices[iface.name]
@@ -1188,31 +1186,31 @@ def writeDefiner(f, conf, stringtable, i
     f.write("\n    };\n\n")
     f.write("// Make sure our table indices aren't overflowed\n"
             "PR_STATIC_ASSERT((sizeof(tableData) / sizeof(tableData[0])) < (1 << (8 * sizeof(tableData[0].parentInterface))));\n"
             "PR_STATIC_ASSERT((sizeof(tableData) / sizeof(tableData[0])) < (1 << (8 * sizeof(tableData[0].chain))));\n\n")
 
     # The string table for property and method names.
     table_name = "stringtab"
     stringtable.writeDefinition(f, table_name)
-    structNames = [prop_array_name, func_array_name]
+    structNames = [func_array_name]
     for name in structNames:
         f.write("PR_STATIC_ASSERT(sizeof(%s) < (1 << (8 * sizeof(%s[0].name_index))));\n"
                 % (table_name, name))
     f.write("\n")
 
     # the definer function (entry point to this quick stubs file)
     f.write("namespace xpc {\n")
     f.write("bool %s_DefineQuickStubs(" % conf.name)
     f.write("JSContext *cx, JSObject *proto, unsigned flags, uint32_t count, "
             "const nsID **iids)\n"
             "{\n")
     f.write("    return !!xpc_qsDefineQuickStubs("
             "cx, proto, flags, count, iids, %d, tableData, %s, %s, %s);\n" % (
-            size, prop_array_name, func_array_name, table_name))
+            size, "nullptr", func_array_name, table_name))
     f.write("}\n")
     f.write("} // namespace xpc\n\n\n")
 
 
 stubTopTemplate = '''\
 /* THIS FILE IS AUTOGENERATED - DO NOT EDIT */
 #include "jsapi.h"
 #include "qsWinUndefs.h"
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2963,18 +2963,17 @@ xpc_JSObjectToID(JSContext *cx, JSObject
 
 extern bool
 xpc_JSObjectIsID(JSContext *cx, JSObject* obj);
 
 /***************************************************************************/
 // in XPCDebug.cpp
 
 extern bool
-xpc_DumpJSStack(JSContext* cx, bool showArgs, bool showLocals,
-                bool showThisProps);
+xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps);
 
 // Return a newly-allocated string containing a representation of the
 // current JS stack.  It is the *caller's* responsibility to free this
 // string with JS_smprintf_free().
 extern char*
 xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals,
                  bool showThisProps);
 
--- a/js/xpconnect/tests/chrome/test_bug760109.xul
+++ b/js/xpconnect/tests/chrome/test_bug760109.xul
@@ -34,41 +34,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     // Check |constructor|.
     // Note that the 'constructor' property of the underlying chrome object
     // will be resolved on SomeConstructor.prototype, which has an empty
     // __exposedProps__. This means that we shouldn't remap the property, even
     // though we'd also be able to find it on Object.prototype. Some recent
     // refactoring has made it possible to do the right thing here.
     is(typeof chromeObject.constructor, "undefined", "Object constructor does what we expect");
     ok(chromeArray.constructor === Array, "Array constructor remapped properly");
-
-    // We should be able to .forEach on the Array.
-    var concat = '';
-    chromeArray.forEach(function(val) { concat += val; });
-    is(concat, 'abz', "Should be able to .forEach COW-ed Array");
-
-    // Try other Array operations.
-    is(chromeArray.indexOf('b'), 1, "indexOf works correctly");
-    is(chromeArray.join(''), concat, "join works correctly");
-    is(chromeArray.slice(1).join(''), 'bz', "slice works correctly");
-    is(chromeArray.length, 3, "Able to check array length");
-
-    // Try some operations that modify the array.
-    is(chromeArray.pop(), 'z', "Able to call pop");
-    is(chromeArray.push('z'), 3, "Able to call push");
-    chromeArray.reverse();
-    is(chromeArray.join(''), 'zba', "Able to call reverse");
-    chromeArray.sort();
-    is(chromeArray.join(''), 'abz', "Able to call sort");
-
-    // We should be able to .hasOwnProperty on the Object, and have
-    // it filter the objects we can see.
-    ok(chromeObject.hasOwnProperty('foo'), "Should see r property");
-    ok(!chromeObject.hasOwnProperty('bar'), "Shouldn't see non-exposed property");
-    ok(chromeObject.hasOwnProperty('baz'), "Should see rw property");
   }
 
   // We use a constructor to create the test object so that there's an
   // intermediate object on the prototype chain between the instance and the
   // standard prototype.
   function SomeConstructor() {
     this.foo = 2;
     this.bar = 3;
--- a/js/xpconnect/tests/chrome/test_cows.xul
+++ b/js/xpconnect/tests/chrome/test_cows.xul
@@ -263,49 +263,16 @@ function COWTests() {
 
     // Readables and functions
     try {
         var COWFunc = getCOW((function() { return 5; }));
         is(COWFunc(), 5, "COWed functions should be callable");
     } catch (e) {
         todo(false, "COWed functions should not raise " + e);
     }
-    try {
-        var objWithFunc = {__exposedProps__: {foo: 'r'},
-                           foo: function foo() { return 5; }};
-        is(getCOW((objWithFunc)).foo(), 5,
-           "Readable function exposed props should be callable");
-    } catch (e) {
-        ok(false, "Readable function exposed props should be callable" + e);
-    }
-
-    // Readables with getters
-    var obj = {
-        get prop() { return { __exposedProps__: {}, test: "FAIL" } },
-        __exposedProps__: {prop: 'r'}
-    };
-    is(getCOW(obj).prop.test, undefined, "getting prop.test shouldn't return anything");
-    ok(!("test" in getCOW(obj).prop), "getting prop.test shouldn't return anything");
-
-    // Alien objects
-    try {
-        is(alienObject.funProp(1), 2,
-           "COWs wrapping objects from different principals should work");
-    } catch (e) {
-        ok(false, "COWs wrapping objs from different principals " +
-                  "shouldn't throw " + e);
-    }
-
-    try {
-        is(alienObject.funProp(1), 2,
-           "COWs wrapping objs from different principals should work twice");
-    } catch (e) {
-        ok(false, "COWs wrapping objs from different principals " +
-                  "shouldn't throw on second access but not first: " + e);
-    }
 }
 
 // Decompile the COW test suite, re-evaluate it in the sandbox and execute it.
 Cu.evalInSandbox('(' + uneval(COWTests) + ')()', sandbox);
 
 // Test that COWed objects passing from content to chrome get unwrapped.
 function returnCOW() {
     return getCOW({__exposedProps__: {},
--- a/js/xpconnect/tests/chrome/test_exposeInDerived.xul
+++ b/js/xpconnect/tests/chrome/test_exposeInDerived.xul
@@ -22,31 +22,25 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   // Set up the sandbox.
   var sb = new Cu.Sandbox('http://www.example.com');
   sb.ok = ok;
   sb.is = is;
 
   // Make a chrome object that exposes objects off its prototype.
   sb.proto = { read: 42, readWrite: 32, __exposedProps__: {} };
-  sb.proto.__defineSetter__('setterProp', function(val) { this._setterProp = val; });
-  sb.obj = { __exposedProps__: { read: 'r', readWrite: 'rw', setterProp: 'w' } };
+  sb.obj = { __exposedProps__: { read: 'r', readWrite: 'rw' } };
   sb.obj.__proto__ = sb.proto;
 
   // Make sure we can't access any of the properties on the prototype directly.
   Cu.evalInSandbox('is(proto.read, undefined, "proto.read inaccessible");', sb);
   Cu.evalInSandbox('var wrote = false; ' +
                    'try { proto.readWrite = 12; wrote = true; } catch(e) {} ' +
                    ' ok(!wrote, "Should not write proto property");', sb);
-  Cu.evalInSandbox('var wrote = false; ' +
-                   'try { proto.setterProp = 12; wrote = true; } catch(e) {} ' +
-                   ' ok(!wrote, "Should not write proto setter");', sb);
 
   // Make sure we can access the exposed properties via the derived object.
   Cu.evalInSandbox('is(obj.read, 42, "obj.read accessible");', sb);
   Cu.evalInSandbox('is(obj.readWrite, 32, "obj.readWrite is readable");', sb);
   Cu.evalInSandbox('obj.readWrite = 8; is(obj.readWrite, 8, "obj.readWrite is writable");', sb);
-  Cu.evalInSandbox('obj.setterProp = 3;', sb);
-  is(sb.obj._setterProp, 3, "obj.setterProp works");
 
   ]]>
   </script>
 </window>
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -108,23 +108,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     ok(Object.getOwnPropertyNames(iwin.Array).indexOf('prototype') >= 0, "Should list prototype for standard constructor");
 
     // Test proxies.
     var targetObject = new iwin.Object();
     targetObject.foo = 9;
     var forwardingProxy = new iwin.Proxy(targetObject, new iwin.Object());
     is(global(forwardingProxy), iwin, "proxy global correct");
     is(Cu.waiveXrays(forwardingProxy).foo, 9, "forwards correctly");
-    // NB: COW-implemented proxy handlers are super dangerous, and we should not
-    // encourage them.
-    var handler = {get: function(target, name) { return name * 2; }, __exposedProps__: {get: 'r'}};
-    var doublingProxy = new iwin.Proxy(targetObject, handler);
-    is(global(doublingProxy), iwin, "doubling proxy global correct");
-    is(Cu.waiveXrays(doublingProxy)[3], 6, "Doubles correctly");
-    is(Cu.waiveXrays(doublingProxy)[20], 40, "Doubles correctly");
 
     // Test eval.
     var toEval = "({a: 2, b: {foo: 'bar'}, f: function() { return window; }})";
     is(global(iwin.eval(toEval)), iwin, "eval creates objects in the correct global");
     is(iwin.eval(toEval).b.foo, 'bar', "eval-ed object looks right");
     is(Cu.waiveXrays(iwin.eval(toEval)).f(), Cu.waiveXrays(iwin), "evaled function works right");
 
     testDate();
--- a/js/xpconnect/tests/mochitest/test_bug393269.html
+++ b/js/xpconnect/tests/mochitest/test_bug393269.html
@@ -9,18 +9,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   <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=393269">Mozilla Bug 393269</a>
 <iframe id="ifr"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-SimpleTest.expectAssertions(1, 2);
-
 (function () {
     /** Test for Bug 393269 **/
     var doc = $("ifr").contentDocument;
     is("UTF-8", doc.characterSet, "control, getting a property");
     doc.open();
     try {
         is("UTF-8", doc.characterSet,
            "can get a property after 1 document.open")
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_bug1082450.js
@@ -0,0 +1,40 @@
+const Cu = Components.utils;
+function run_test() {
+
+  var sb = new Cu.Sandbox('http://www.example.com');
+  function checkThrows(str, rgxp) {
+    try {
+      sb.eval(str);
+      do_check_true(false);
+    } catch (e) {
+      do_check_true(rgxp.test(e));
+    }
+  }
+
+  sb.exposed = {
+    get getterProp() { return 42; },
+    set setterProp(x) { },
+    get getterSetterProp() { return 42; },
+    set getterSetterProp(x) { },
+    simpleValueProp: 42,
+    objectValueProp: { val: 42, __exposedProps__: { val: 'r' } },
+    contentCallableValueProp: new sb.Function('return 42'),
+    chromeCallableValueProp: function() {},
+    __exposedProps__: { getterProp : 'r',
+                        setterProp : 'w',
+                        getterSetterProp: 'rw',
+                        simpleValueProp: 'r',
+                        objectValueProp: 'r',
+                        contentCallableValueProp: 'r',
+                        chromeCallableValueProp: 'r' }
+  };
+
+  do_check_eq(sb.eval('exposed.simpleValueProp'), 42);
+  do_check_eq(sb.eval('exposed.objectValueProp.val'), 42);
+  checkThrows('exposed.getterProp;', /privileged accessor/i);
+  checkThrows('exposed.setterProp = 42;', /privileged accessor/i);
+  checkThrows('exposed.getterSetterProp;', /privileged accessor/i);
+  checkThrows('exposed.getterSetterProp = 42;', /privileged accessor/i);
+  do_check_eq(sb.eval('exposed.contentCallableValueProp()'), 42);
+  checkThrows('exposed.chromeCallableValueProp();', /privileged or cross-origin callable/i);
+}
--- a/js/xpconnect/tests/unit/test_bug780370.js
+++ b/js/xpconnect/tests/unit/test_bug780370.js
@@ -1,23 +1,23 @@
 /* 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/. */
 
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=780370 */
 
 const Cu = Components.utils;
 
-// Use a COW to expose a function from a standard prototype, and make sure it's
-// still remapped.
+// Use a COW to expose a function from a standard prototype, and make we deny
+// access to it.
 
 function run_test()
 {
   var sb = Cu.Sandbox("http://www.example.com");
   sb.obj = { foo: 42, __exposedProps__: { hasOwnProperty: 'r' } };
   do_check_eq(Cu.evalInSandbox('typeof obj.foo', sb), 'undefined', "COW works as expected");
-  do_check_true(Cu.evalInSandbox('obj.hasOwnProperty === Object.prototype.hasOwnProperty', sb),
-                "Remapping happens even when the property is explicitly exposed");
-  // NB: We used to test for the following, but such behavior became very
-  // difficult to implement in a recent refactor. We're moving away from this
-  // API anyway, so we decided to explicitly drop support for this.
-  // do_check_eq(Cu.evalInSandbox('Object.prototype.bar = 10; obj.bar', sb), 10);
+  try {
+    Cu.evalInSandbox('obj.hasOwnProperty', sb);
+    do_check_true(false);
+  } catch (e) {
+    do_check_true(/privileged or cross-origin callable/i.test(e));
+  }
 }
deleted file mode 100644
--- a/js/xpconnect/tests/unit/test_bug805807.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const Cu = Components.utils;
-function run_test() {
-  var sb = new Cu.Sandbox('http://www.example.com');
-
-  sb.obj = { priv: 42, __exposedProps__ : {} };
-  Object.defineProperty(sb.obj, 'readable', { get: function() { return this.priv; }, set: function(x) { this.priv = x; }} );
-  sb.obj.__exposedProps__.readable = 'r';
-  do_check_eq(Cu.evalInSandbox('Object.getOwnPropertyDescriptor(obj, "readable").get.call(obj)', sb), 42);
-  sb.obj.readable = 32;
-  do_check_eq(Cu.evalInSandbox('Object.getOwnPropertyDescriptor(obj, "readable").get.call(obj);', sb), 32);
-  do_check_eq(Cu.evalInSandbox('Object.__lookupGetter__.call(obj, "readable").call(obj);', sb), 32);
-  Object.getOwnPropertyDescriptor(sb.obj, "readable").set.call(sb.obj, 22);
-  do_check_eq(sb.obj.readable, 22);
-  Object.__lookupSetter__.call(sb.obj, "readable").call(sb.obj, 21);
-  do_check_eq(sb.obj.readable, 21);
-  checkThrows(sb, 'obj.readable = 11;');
-  do_check_eq(Cu.evalInSandbox('Object.getOwnPropertyDescriptor(obj, "readable").set', sb), null);
-  do_check_eq(Cu.evalInSandbox('Object.__lookupSetter__.call(obj, "readable")', sb), null);
-  do_check_eq(sb.obj.readable, 21);
-}
-
-function checkThrows(sb, expression) {
-  var result = Cu.evalInSandbox('(function() { try { ' + expression + ' return "success"; } catch (e) { return e.toString(); } })();', sb);
-  dump("Result: " + result);
-  do_check_true(!!/denied/.exec(result));
-}
--- a/js/xpconnect/tests/unit/test_bug853709.js
+++ b/js/xpconnect/tests/unit/test_bug853709.js
@@ -1,16 +1,12 @@
 const Cu = Components.utils;
 
 function setupChromeSandbox() {
   this.chromeObj = {a: 2, __exposedProps__: {a: "rw", b: "rw"} };
-  this._b = 3;
-  Object.defineProperty(chromeObj, 'b', { configurable: true,
-                                          get: function() { return _b; },
-                                          set: function(val) { _b = val; } });
   this.chromeArr = [4, 2, 1];
   this.chromeArr["__exposedProps__"] = { "1": "rw" };
 }
 
 function checkDefineThrows(sb, obj, prop, desc) {
   var result = Cu.evalInSandbox('(function() { try { Object.defineProperty(' + obj + ', "' + prop + '", ' + desc.toSource() + '); return "nothrow"; } catch (e) { return e.toString(); }})();', sb);
   do_check_neq(result, 'nothrow');
   do_check_true(!!/denied/.exec(result));
@@ -20,17 +16,15 @@ function checkDefineThrows(sb, obj, prop
 function run_test() {
   var chromeSB = new Cu.Sandbox(this);
   var contentSB = new Cu.Sandbox('http://www.example.org');
   Cu.evalInSandbox('(' + setupChromeSandbox.toSource() + ')()', chromeSB);
   contentSB.chromeObj = chromeSB.chromeObj;
   contentSB.chromeArr = chromeSB.chromeArr;
 
   do_check_eq(Cu.evalInSandbox('chromeObj.a', contentSB), 2);
-  do_check_eq(Cu.evalInSandbox('chromeObj.b', contentSB), 3);
-  do_check_eq(Cu.evalInSandbox('chromeObj.b = 4; chromeObj.b', contentSB), 4);
   do_check_eq(Cu.evalInSandbox('chromeArr[1]', contentSB), 2);
 
   checkDefineThrows(contentSB, 'chromeObj', 'a', {get: function() { return 2; }});
   checkDefineThrows(contentSB, 'chromeObj', 'a', {configurable: true, get: function() { return 2; }});
   checkDefineThrows(contentSB, 'chromeObj', 'b', {configurable: true, get: function() { return 2; }, set: function() {}});
   checkDefineThrows(contentSB, 'chromeArr', '1', {configurable: true, get: function() { return 2; }});
 }
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -23,17 +23,16 @@ support-files =
 [test_bug451678.js]
 [test_bug604362.js]
 [test_bug641378.js]
 [test_bug677864.js]
 [test_bug711404.js]
 [test_bug742444.js]
 [test_bug778409.js]
 [test_bug780370.js]
-[test_bug805807.js]
 [test_bug809652.js]
 [test_bug809674.js]
 [test_bug813901.js]
 [test_bug845201.js]
 [test_bug845862.js]
 [test_bug849730.js]
 [test_bug851895.js]
 [test_bug853709.js]
@@ -47,16 +46,17 @@ support-files =
 [test_bug961054.js]
 [test_bug976151.js]
 [test_bug1001094.js]
 [test_bug1021312.js]
 [test_bug1033253.js]
 [test_bug1033920.js]
 [test_bug1033927.js]
 [test_bug1034262.js]
+[test_bug1082450.js]
 [test_bug_442086.js]
 [test_file.js]
 [test_blob.js]
 [test_blob2.js]
 [test_file2.js]
 [test_import.js]
 [test_import_fail.js]
 [test_interposition.js]
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -338,16 +338,35 @@ ExposedPropertiesOnly::check(JSContext *
         return false;
     }
 
     if ((act == Wrapper::SET && !(access & WRITE)) ||
         (act != Wrapper::SET && !(access & READ))) {
         return false;
     }
 
+    // Inspect the property on the underlying object to check for red flags.
+    if (!JS_GetPropertyDescriptorById(cx, wrappedObject, id, &desc))
+        return false;
+
+    // Reject accessor properties.
+    if (desc.hasGetterOrSetter()) {
+        EnterAndThrow(cx, wrapper, "Exposing privileged accessor properties is prohibited");
+        return false;
+    }
+
+    // Reject privileged or cross-origin callables.
+    if (desc.value().isObject()) {
+        RootedObject maybeCallable(cx, js::UncheckedUnwrap(&desc.value().toObject()));
+        if (JS::IsCallable(maybeCallable) && !AccessCheck::subsumes(wrapper, maybeCallable)) {
+            EnterAndThrow(cx, wrapper, "Exposing privileged or cross-origin callable is prohibited");
+            return false;
+        }
+    }
+
     return true;
 }
 
 bool
 ExposedPropertiesOnly::deny(js::Wrapper::Action act, HandleId id)
 {
     // Fail silently for GET, ENUMERATE, and GET_PROPERTY_DESCRIPTOR.
     if (act == js::Wrapper::GET || act == js::Wrapper::ENUMERATE ||
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -281,18 +281,18 @@ ChromeObjectWrapper::objectClassIs(Handl
 bool
 ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper,
                            HandleId id, js::Wrapper::Action act, bool *bp) const
 {
     if (AllowedByBase(cx, wrapper, id, act))
         return true;
     // COWs fail silently for GETs, and that also happens to be the only case
     // where we might want to redirect the lookup to the home prototype chain.
-    *bp = act == Wrapper::GET || act == Wrapper::ENUMERATE ||
-          act == Wrapper::GET_PROPERTY_DESCRIPTOR;
+    *bp = (act == Wrapper::GET || act == Wrapper::ENUMERATE ||
+           act == Wrapper::GET_PROPERTY_DESCRIPTOR) && !JS_IsExceptionPending(cx);
     if (!*bp || id == JSID_VOID)
         return false;
 
     // Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor
     // before we've fully entered the policy. Waive our policy.
     js::AutoWaivePolicy policy(cx, wrapper, id, act);
     return PropIsFromStandardPrototype(cx, wrapper, id);
 }
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug1080361_inner.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1080361
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1080361</title>
+  <meta name="author" content="Maksim Lebedev" />
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+    #target, #mediator, #listener { background: yellow; margin: 10px; }
+  </style>
+  <script type="application/javascript">
+    var target = undefined;
+    var mediator = undefined;
+    var listener = undefined;
+    var test_target_down = false;
+    var test_target_up = false;
+    var test_first_exc = false;
+    var test_second_exc = false;
+    var test_third_exc = false;
+    var test_fourth_exc = false;
+    var test_listener = false;
+
+    function TargetDownHandler(event) {
+      logger("Target receive event: " + event.type);
+      test_target_down = true;
+      try {
+        logger("target.setPointerCapture()");
+        target.setPointerCapture(31415);
+      } catch(exc) {
+        test_first_exc = true;
+        parent.is(exc.name, "InvalidPointerId", "Exception InvalidPointerId should be fired");
+      }
+      try {
+        logger("mediator.setPointerCapture()");
+        mediator.parentNode.removeChild(mediator);
+        mediator.setPointerCapture(event.pointerId);
+      } catch(exc) {
+        test_second_exc = true;
+        parent.is(exc.name, "InvalidStateError", "Exception InvalidStateError should be fired");
+      }
+      try {
+        logger("listener.setPointerCapture()");
+        listener.setPointerCapture(event.pointerId);
+      } catch(exc) {
+        test_third_exc = true;
+      }
+    }
+    function TargetUpHandler(event) {
+      logger("Target receive event: " + event.type);
+      test_target_up = true;
+      try {
+        logger("target.setPointerCapture()");
+        target.setPointerCapture(event.pointerId);
+      } catch(exc) {
+        test_fourth_exc = true;
+      }
+    }
+    function ListenerHandler(event) {
+      logger("Listener receive event: " + event.type);
+      test_listener = true;
+      listener.releasePointerCapture(event.pointerId);
+    }
+    function logger(message) {
+      console.log(message);
+      var log = document.getElementById('log');
+      log.innerHTML = message + "<br>" + log.innerHTML;
+    }
+
+    function prepareTest() {
+      parent.turnOnPointerEvents(executeTest);
+    }
+    function executeTest()
+    {
+      logger("executeTest");
+      target = document.getElementById("target");
+      mediator = document.getElementById("mediator");
+      listener = document.getElementById("listener");
+      target.addEventListener("pointerdown",          TargetDownHandler,  false);
+      target.addEventListener("pointerup",            TargetUpHandler,    false);
+      listener.addEventListener("gotpointercapture",  ListenerHandler,    false);
+      var rect = target.getBoundingClientRect();
+      synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerdown"});
+      synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointermove"});
+      synthesizePointer(target, rect.width/2, rect.height/2, {type: "pointerup"});
+      finishTest();
+    }
+    function finishTest() {
+      setTimeout(function() {
+        parent.is(test_target_down, true,   "pointerdown event should be received by target");
+        parent.is(test_target_up,   true,   "pointerup event should be received by target");
+        parent.is(test_first_exc,   true,   "first exception should be thrown");
+        parent.is(test_second_exc,  true,   "second exception should be thrown");
+        parent.is(test_third_exc,   false,  "third exception should not be thrown");
+        parent.is(test_fourth_exc,  false,  "fourth exception should not be thrown");
+        parent.is(test_listener,    true,   "listener should receive gotpointercapture event");
+        logger("finishTest");
+        parent.finishTest();
+      }, 1000);
+    }
+  </script>
+</head>
+<body onload="prepareTest()">
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080361">Mozilla Bug 1080361</a>
+  <div id="target">div id=target</div>
+  <div id="mediator">div id=mediator</div>
+  <div id="listener">div id=listener</div>
+  <pre id="log"></pre>
+</body>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -486,8 +486,10 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug687297.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 948948
 support-files =
   bug687297_a.html
   bug687297_b.html
   bug687297_c.html
 [test_bug990340.html]
 [test_bug1070851.html]
+[test_bug1080361.html]
+support-files = bug1080361_inner.html
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug1080361.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1080361
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1080361</title>
+    <meta name="author" content="Maksim Lebedev" />
+    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      var iframe = undefined;
+      function prepareTest() {
+        SimpleTest.waitForExplicitFinish();
+        iframe = document.getElementById("testFrame");
+        turnOnPointerEvents(startTest);
+      }
+      function turnOnPointerEvents(callback) {
+        SpecialPowers.pushPrefEnv({
+          "set": [
+            ["dom.w3c_pointer_events.enabled", true]
+          ]
+        }, callback);
+      }
+      function startTest() {
+        iframe.src = "bug1080361_inner.html";
+      }
+      function finishTest() {
+        SimpleTest.finish();
+      }
+    </script>
+  </head>
+  <body onload="prepareTest()">
+    <iframe id="testFrame" height="700" width="700"></iframe>
+  </body>
+</html>
--- a/layout/reftests/invalidation/540247-1-ref.xul
+++ b/layout/reftests/invalidation/540247-1-ref.xul
@@ -4,18 +4,17 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
 <script><![CDATA[
 document.addEventListener("MozReftestInvalidate", runtest, false);
 
 function runtest() {
   document.getElementById('b').height = '100';
 
-  var sbo = document.getElementById('s').boxObject.
-              QueryInterface(Components.interfaces.nsIScrollBoxObject);
+  var sbo = document.getElementById('s').boxObject;
   sbo.scrollTo(0, 1000);
 
   document.documentElement.className = "";
 }
 ]]>
 </script>
 
   <scrollbox id="s" height="200" style="overflow: scroll;">
--- a/layout/reftests/invalidation/540247-1.xul
+++ b/layout/reftests/invalidation/540247-1.xul
@@ -5,18 +5,17 @@
 
 <script><![CDATA[
 document.addEventListener("MozReftestInvalidate", runtest, false);
 
 function runtest() {
   // Make sure that the effects of the scroll are painted to the screen before
   // shrinking the size of the scrolled frame.
   window.addEventListener("MozAfterPaint", finish, false);
-  var sbo = document.getElementById('s').boxObject.
-              QueryInterface(Components.interfaces.nsIScrollBoxObject);
+  var sbo = document.getElementById('s').boxObject;
   sbo.scrollTo(0, 1000);
 }
 
 function finish() {
   document.getElementById('b').height = '100';
   document.documentElement.className = "";
 }
 ]]>
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -960,16 +960,17 @@ protected:
   }
   bool IsParsingCompoundProperty(void) const {
     return mParsingCompoundProperty;
   }
 
   /* Functions for basic shapes */
   bool ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens);
   bool ParsePolygonFunction(nsCSSValue& aValue);
+  bool ParseCircleOrEllipseFunction(nsCSSKeyword, nsCSSValue& aValue);
 
   /* Functions for transform Parsing */
   bool ParseSingleTransform(bool aIsPrefixed, nsCSSValue& aValue);
   bool ParseFunction(nsCSSKeyword aFunction, const int32_t aAllowedTypes[],
                      int32_t aVariantMaskAll, uint16_t aMinElems,
                      uint16_t aMaxElems, nsCSSValue &aValue);
   bool ParseFunctionInternals(const int32_t aVariantMask[],
                               int32_t aVariantMaskAll,
@@ -13839,16 +13840,73 @@ CSSParserImpl::ParsePolygonFunction(nsCS
   if (numArgs > 1) {
     functionArray->Item(1) = fillRuleValue;
   }
 
   return true;
 }
 
 bool
+CSSParserImpl::ParseCircleOrEllipseFunction(nsCSSKeyword aKeyword,
+                                            nsCSSValue& aValue)
+{
+  nsCSSValue radiusX, radiusY, position;
+  bool hasRadius = false, hasPosition = false;
+
+  int32_t mask = VARIANT_LPCALC | VARIANT_NONNEGATIVE_DIMENSION |
+                 VARIANT_KEYWORD;
+  if (ParseVariant(radiusX, mask, nsCSSProps::kShapeRadiusKTable)) {
+    if (aKeyword == eCSSKeyword_ellipse) {
+      if (!ParseVariant(radiusY, mask, nsCSSProps::kShapeRadiusKTable)) {
+        REPORT_UNEXPECTED_TOKEN(PEExpectedRadius);
+        SkipUntil(')');
+        return false;
+      }
+    }
+    hasRadius = true;
+  }
+
+  if (!ExpectSymbol(')', true)) {
+    if (!GetToken(true)) {
+      REPORT_UNEXPECTED_EOF(PEPositionEOF);
+      return false;
+    }
+
+    if (mToken.mType != eCSSToken_Ident ||
+        !mToken.mIdent.LowerCaseEqualsLiteral("at") ||
+        !ParsePositionValue(position)) {
+      REPORT_UNEXPECTED_TOKEN(PEExpectedPosition);
+      SkipUntil(')');
+      return false;
+    }
+    if (!ExpectSymbol(')', true)) {
+      REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen);
+      SkipUntil(')');
+      return false;
+    }
+    hasPosition = true;
+  }
+
+  size_t count = aKeyword == eCSSKeyword_circle ? 2 : 3;
+  nsRefPtr<nsCSSValue::Array> functionArray =
+    aValue.InitFunction(aKeyword, count);
+  if (hasRadius) {
+    functionArray->Item(1) = radiusX;
+    if (aKeyword == eCSSKeyword_ellipse) {
+      functionArray->Item(2) = radiusY;
+    }
+  }
+  if (hasPosition) {
+    functionArray->Item(count) = position;
+  }
+
+  return true;
+}
+
+bool
 CSSParserImpl::ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens)
 {
   if (!GetToken(true)) {
     return false;
   }
 
   if (mToken.mType != eCSSToken_Function) {
     UngetToken();
@@ -13856,16 +13914,19 @@ CSSParserImpl::ParseBasicShape(nsCSSValu
   }
 
   // Specific shape function parsing always consumes tokens.
   *aConsumedTokens = true;
   nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
   switch (keyword) {
   case eCSSKeyword_polygon:
     return ParsePolygonFunction(aValue);
+  case eCSSKeyword_circle:
+  case eCSSKeyword_ellipse:
+    return ParseCircleOrEllipseFunction(keyword, aValue);
   default:
     return false;
   }
 }
 
 /* Parse a clip-path url to a <clipPath> element or a basic shape. */
 bool CSSParserImpl::ParseClipPath()
 {
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1886,16 +1886,22 @@ const KTableValue nsCSSProps::kClipShape
   eCSSKeyword_border_box,    NS_STYLE_CLIP_SHAPE_SIZING_BORDER,
   eCSSKeyword_margin_box,    NS_STYLE_CLIP_SHAPE_SIZING_MARGIN,
   eCSSKeyword_fill_box,      NS_STYLE_CLIP_SHAPE_SIZING_FILL,
   eCSSKeyword_stroke_box,    NS_STYLE_CLIP_SHAPE_SIZING_STROKE,
   eCSSKeyword_view_box,      NS_STYLE_CLIP_SHAPE_SIZING_VIEW,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const KTableValue nsCSSProps::kShapeRadiusKTable[] = {
+  eCSSKeyword_closest_side, NS_RADIUS_CLOSEST_SIDE,
+  eCSSKeyword_farthest_side, NS_RADIUS_FARTHEST_SIDE,
+  eCSSKeyword_UNKNOWN, -1
+};
+
 const KTableValue nsCSSProps::kFilterFunctionKTable[] = {
   eCSSKeyword_blur, NS_STYLE_FILTER_BLUR,
   eCSSKeyword_brightness, NS_STYLE_FILTER_BRIGHTNESS,
   eCSSKeyword_contrast, NS_STYLE_FILTER_CONTRAST,
   eCSSKeyword_grayscale, NS_STYLE_FILTER_GRAYSCALE,
   eCSSKeyword_invert, NS_STYLE_FILTER_INVERT,
   eCSSKeyword_opacity, NS_STYLE_FILTER_OPACITY,
   eCSSKeyword_saturate, NS_STYLE_FILTER_SATURATE,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -532,16 +532,17 @@ public:
   static const KTableValue kBorderWidthKTable[];
   static const KTableValue kBoxAlignKTable[];
   static const KTableValue kBoxDecorationBreakKTable[];
   static const KTableValue kBoxDirectionKTable[];
   static const KTableValue kBoxOrientKTable[];
   static const KTableValue kBoxPackKTable[];
   static const KTableValue kClipShapeSizingKTable[];
   static const KTableValue kDominantBaselineKTable[];
+  static const KTableValue kShapeRadiusKTable[];
   static const KTableValue kFillRuleKTable[];
   static const KTableValue kFilterFunctionKTable[];
   static const KTableValue kImageRenderingKTable[];
   static const KTableValue kShapeRenderingKTable[];
   static const KTableValue kStrokeLinecapKTable[];
   static const KTableValue kStrokeLinejoinKTable[];
   static const KTableValue kStrokeContextValueKTable[];
   static const KTableValue kVectorEffectKTable[];
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -847,16 +847,66 @@ nsCSSValue::AppendPolygonToString(nsCSSP
                                                   nsCSSProps::kFillRuleKTable),
                        aResult);
     aResult.AppendLiteral(", ");
     ++index;
   }
   array->Item(index).AppendToString(aProperty, aResult, aSerialization);
 }
 
+inline void
+nsCSSValue::AppendPositionCoordinateToString(
+                const nsCSSValue& aValue, nsCSSProperty aProperty,
+                nsAString& aResult, Serialization aSerialization) const
+{
+  if (aValue.GetUnit() == eCSSUnit_Enumerated) {
+    int32_t intValue = aValue.GetIntValue();
+    AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(intValue,
+                          nsCSSProps::kShapeRadiusKTable), aResult);
+  } else {
+    aValue.AppendToString(aProperty, aResult, aSerialization);
+  }
+}
+
+void
+nsCSSValue::AppendCircleOrEllipseToString(nsCSSKeyword aFunctionId,
+                                          nsCSSProperty aProperty,
+                                          nsAString& aResult,
+                                          Serialization aSerialization) const
+{
+  const nsCSSValue::Array* array = GetArrayValue();
+  size_t count = aFunctionId == eCSSKeyword_circle ? 2 : 3;
+  NS_ABORT_IF_FALSE(array->Count() == count + 1, "wrong number of arguments");
+
+  bool hasRadii = array->Item(1).GetUnit() != eCSSUnit_Null;
+
+  AppendPositionCoordinateToString(array->Item(1), aProperty,
+                                     aResult, aSerialization);
+
+  if (hasRadii && aFunctionId == eCSSKeyword_ellipse) {
+    aResult.Append(' ');
+    AppendPositionCoordinateToString(array->Item(2), aProperty,
+                                     aResult, aSerialization);
+  }
+
+  // Any position specified?
+  if (array->Item(count).GetUnit() != eCSSUnit_Array) {
+    NS_ABORT_IF_FALSE(array->Item(count).GetUnit() == eCSSUnit_Null,
+                      "unexpected value");
+    return;
+  }
+
+  if (hasRadii) {
+    aResult.Append(' ');
+  }
+  aResult.AppendLiteral("at ");
+  array->Item(count).AppendToString(eCSSProperty_background_position,
+                                    aResult, aSerialization);
+}
+
 void
 nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
                            Serialization aSerialization) const
 {
   // eCSSProperty_UNKNOWN gets used for some recursive calls below.
   NS_ABORT_IF_FALSE((0 <= aProperty &&
                      aProperty <= eCSSProperty_COUNT_no_shorthands) ||
                     aProperty == eCSSProperty_UNKNOWN,
@@ -986,16 +1036,22 @@ nsCSSValue::AppendToString(nsCSSProperty
     nsStyleUtil::AppendEscapedCSSIdent(ident, aResult);
     aResult.Append('(');
 
     switch (functionId) {
       case eCSSKeyword_polygon:
         AppendPolygonToString(aProperty, aResult, aSerialization);
         break;
 
+      case eCSSKeyword_circle:
+      case eCSSKeyword_ellipse:
+        AppendCircleOrEllipseToString(functionId, aProperty, aResult,
+                                      aSerialization);
+        break;
+
       default: {
         // Now, step through the function contents, writing each of
         // them as we go.
         for (size_t index = 1; index < array->Count(); ++index) {
           array->Item(index).AppendToString(aProperty, aResult,
                                             aSerialization);
 
           /* If we're not at the final element, append a comma. */
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -716,17 +716,24 @@ public:
 
 private:
   static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
     return static_cast<char16_t*>(aBuffer->Data());
   }
 
   void AppendPolygonToString(nsCSSProperty aProperty, nsAString& aResult,
                              Serialization aValueSerialization) const;
-
+  void AppendPositionCoordinateToString(const nsCSSValue& aValue,
+                                        nsCSSProperty aProperty,
+                                        nsAString& aResult,
+                                        Serialization aSerialization) const;
+  void AppendCircleOrEllipseToString(
+           nsCSSKeyword aFunctionId,
+           nsCSSProperty aProperty, nsAString& aResult,
+           Serialization aValueSerialization) const;
 protected:
   nsCSSUnit mUnit;
   union {
     int32_t    mInt;
     float      mFloat;
     // Note: the capacity of the buffer may exceed the length of the string.
     // If we're of a string type, mString is not null.
     nsStringBuffer* mString;
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5170,51 +5170,103 @@ nsComputedDOMStyle::DoGetLightingColor()
 CSSValue*
 nsComputedDOMStyle::DoGetStopColor()
 {
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleSVGReset()->mStopColor);
   return val;
 }
 
+inline void AppendBasicShapeTypeToString(nsStyleBasicShape::Type aType,
+                                         nsAutoString& aString)
+{
+  nsCSSKeyword functionName;
+  switch (aType) {
+    case nsStyleBasicShape::Type::ePolygon:
+      functionName = eCSSKeyword_polygon;
+      break;
+    case nsStyleBasicShape::Type::eCircle:
+      functionName = eCSSKeyword_circle;
+      break;
+    case nsStyleBasicShape::Type::eEllipse:
+      functionName = eCSSKeyword_ellipse;
+      break;
+    default:
+      NS_NOTREACHED("unexpected type");
+  }
+  AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(functionName),
+                     aString);
+}
+
 CSSValue*
 nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
   const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
 {
   nsDOMCSSValueList* valueList = GetROCSSValueList(false);
-
-  if (aStyleBasicShape &&
-      aStyleBasicShape->GetShapeType() == nsStyleBasicShape::Type::ePolygon) {
+  if (aStyleBasicShape) {
+    nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
     // Shape function name and opening parenthesis.
     nsAutoString shapeFunctionString;
-    AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(eCSSKeyword_polygon),
-                       shapeFunctionString);
+    AppendBasicShapeTypeToString(type, shapeFunctionString);
     shapeFunctionString.Append('(');
-    bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
-                          NS_STYLE_FILL_RULE_EVENODD;
-    if (hasEvenOdd) {
-      shapeFunctionString.AppendLiteral("evenodd");
-    }
-    for (size_t i = 0; i < aStyleBasicShape->Coordinates().Length(); i += 2) {
-      nsAutoString coordString;
-      if (i > 0 || hasEvenOdd) {
-        shapeFunctionString.AppendLiteral(", ");
+    switch (type) {
+      case nsStyleBasicShape::Type::ePolygon: {
+        bool hasEvenOdd = aStyleBasicShape->GetFillRule() ==
+                              NS_STYLE_FILL_RULE_EVENODD;
+        if (hasEvenOdd) {
+          shapeFunctionString.AppendLiteral("evenodd");
+        }
+        for (size_t i = 0;
+             i < aStyleBasicShape->Coordinates().Length(); i += 2) {
+          nsAutoString coordString;
+          if (i > 0 || hasEvenOdd) {
+            shapeFunctionString.AppendLiteral(", ");
+          }
+          SetCssTextToCoord(coordString,
+                            aStyleBasicShape->Coordinates()[i]);
+          shapeFunctionString.Append(coordString);
+          shapeFunctionString.Append(' ');
+          SetCssTextToCoord(coordString,
+                            aStyleBasicShape->Coordinates()[i + 1]);
+          shapeFuncti