Merge m-c to b2g-inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 31 Oct 2014 16:32:23 -0400
changeset 213540 cb1711e891162b7b7a6f6750fb3defbe0ea94441
parent 213539 bdd0bf8ed490d9adfd24d7521fb6779c60fa5d7b (current diff)
parent 213433 04a87b6ff211eabb56fad2bba369176d4fa3c8be (diff)
child 213541 4cb1154b019067d2acfa9f66855d088aa6f105e8
push id27755
push userphilringnalda@gmail.com
push dateSun, 02 Nov 2014 17:26:48 +0000
treeherdermozilla-central@0b81c10a9074 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound. a=merge
browser/devtools/performance/performance.js
dom/encoding/test/unit/mochitest.ini
dom/encoding/test/unit/moz.build
dom/html/test/imports/file_cycle_5_A.html
dom/html/test/imports/file_cycle_5_B.html
dom/html/test/imports/file_cycle_5_C.html
dom/html/test/imports/file_cycle_5_D.html
dom/html/test/imports/test_cycle_5.html
dom/inputmethod/mochitest/test_delete_focused_element.html
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -397,32 +397,33 @@ this.EventManager.prototype = {
       // zero-length text. If we did, ignore it (bug #749810).
       if (txtIface.characterCount) {
         throw x;
       }
     }
     // If there are embedded objects in the text, ignore them.
     // Assuming changes to the descendants would already be handled by the
     // show/hide event.
-    let modifiedText = event.modifiedText.replace(/\uFFFC/g, '').trim();
-    if (!modifiedText) {
+    let modifiedText = event.modifiedText.replace(/\uFFFC/g, '');
+    if (modifiedText != event.modifiedText && !modifiedText.trim()) {
       return;
     }
+
     if (aLiveRegion) {
       if (aEvent.eventType === Events.TEXT_REMOVED) {
         this._queueLiveEvent(Events.TEXT_REMOVED, aLiveRegion, aIsPolite,
           modifiedText);
       } else {
         this._dequeueLiveEvent(Events.TEXT_REMOVED, aLiveRegion);
         this.present(Presentation.liveRegion(aLiveRegion, aIsPolite, false,
           modifiedText));
       }
     } else {
-      this.present(Presentation.textChanged(isInserted, event.start,
-        event.length, text, modifiedText));
+      this.present(Presentation.textChanged(aEvent.accessible, isInserted,
+        event.start, event.length, text, modifiedText));
     }
   },
 
   _handleLiveRegion: function _handleLiveRegion(aEvent, aRelevant) {
     if (aEvent.isFromUserInput) {
       return {};
     }
     let parseLiveAttrs = function parseLiveAttrs(aAccessible) {
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -6,18 +6,17 @@
           UtteranceGenerator, BrailleGenerator, States, Roles, PivotContext */
 /* exported Presentation */
 
 'use strict';
 
 const {utils: Cu, interfaces: Ci} = Components;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'Utils', // jshint ignore:line
-  'resource://gre/modules/accessibility/Utils.jsm');
+Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Logger', // jshint ignore:line
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'PivotContext', // jshint ignore:line
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'UtteranceGenerator', // jshint ignore:line
   'resource://gre/modules/accessibility/OutputGenerator.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'BrailleGenerator', // jshint ignore:line
   'resource://gre/modules/accessibility/OutputGenerator.jsm');
@@ -55,18 +54,18 @@ Presenter.prototype = {
    * @param {nsIAccessible} aObject the object that has been invoked.
    * @param {string} aActionName the name of the action.
    */
   actionInvoked: function actionInvoked(aObject, aActionName) {}, // jshint ignore:line
 
   /**
    * Text has changed, either by the user or by the system. TODO.
    */
-  textChanged: function textChanged(aIsInserted, aStartOffset, aLength, aText, // jshint ignore:line
-                                    aModifiedText) {}, // jshint ignore:line
+  textChanged: function textChanged(aAccessible, aIsInserted, aStartOffset, // jshint ignore:line
+                                    aLength, aText, aModifiedText) {}, // jshint ignore:line
 
   /**
    * Text selection has changed. TODO.
    */
   textSelectionChanged: function textSelectionChanged(
     aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput) {}, // jshint ignore:line
 
   /**
@@ -339,17 +338,17 @@ AndroidPresenter.prototype.tabSelected =
 
 AndroidPresenter.prototype.tabStateChanged =
   function AndroidPresenter_tabStateChanged(aDocObj, aPageState) {
     return this.announce(
       UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
   };
 
 AndroidPresenter.prototype.textChanged = function AndroidPresenter_textChanged(
-  aIsInserted, aStart, aLength, aText, aModifiedText) {
+  aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
     let eventDetails = {
       eventType: this.ANDROID_VIEW_TEXT_CHANGED,
       text: [aText],
       fromIndex: aStart,
       removedCount: 0,
       addedCount: 0
     };
 
@@ -456,16 +455,23 @@ AndroidPresenter.prototype.liveRegion =
  * A B2G presenter for Gaia.
  */
 function B2GPresenter() {}
 
 B2GPresenter.prototype = Object.create(Presenter.prototype);
 
 B2GPresenter.prototype.type = 'B2G';
 
+B2GPresenter.prototype.keyboardEchoSetting =
+  new PrefCache('accessibility.accessfu.keyboard_echo');
+B2GPresenter.prototype.NO_ECHO = 0;
+B2GPresenter.prototype.CHARACTER_ECHO = 1;
+B2GPresenter.prototype.WORD_ECHO = 2;
+B2GPresenter.prototype.CHARACTER_AND_WORD_ECHO = 3;
+
 /**
  * A pattern used for haptic feedback.
  * @type {Array}
  */
 B2GPresenter.prototype.PIVOT_CHANGE_HAPTIC_PATTERN = [40];
 
 /**
  * Pivot move reasons.
@@ -492,25 +498,67 @@ B2GPresenter.prototype.pivotChanged =
           isUserInput: aIsUserInput
         }
       }
     };
   };
 
 B2GPresenter.prototype.valueChanged =
   function B2GPresenter_valueChanged(aAccessible) {
+
+    // the editable value changes are handled in the text changed presenter
+    if (Utils.getState(aAccessible).contains(States.EDITABLE)) {
+      return null;
+    }
+
     return {
       type: this.type,
       details: {
         eventType: 'value-change',
         data: aAccessible.value
       }
     };
   };
 
+B2GPresenter.prototype.textChanged = function B2GPresenter_textChanged(
+  aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
+    let echoSetting = this.keyboardEchoSetting.value;
+    let text = '';
+
+    if (echoSetting == this.CHARACTER_ECHO ||
+        echoSetting == this.CHARACTER_AND_WORD_ECHO) {
+      text = aModifiedText;
+    }
+
+    // add word if word boundary is added
+    if ((echoSetting == this.WORD_ECHO ||
+        echoSetting == this.CHARACTER_AND_WORD_ECHO) &&
+        aIsInserted && aLength === 1) {
+      let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
+      let startBefore = {}, endBefore = {};
+      let startAfter = {}, endAfter = {};
+      accText.getTextBeforeOffset(aStart,
+        Ci.nsIAccessibleText.BOUNDARY_WORD_END, startBefore, endBefore);
+      let maybeWord = accText.getTextBeforeOffset(aStart + 1,
+        Ci.nsIAccessibleText.BOUNDARY_WORD_END, startAfter, endAfter);
+      if (endBefore.value !== endAfter.value) {
+        text += maybeWord;
+      }
+    }
+
+    return {
+      type: this.type,
+      details: {
+        eventType: 'text-change',
+        data: text
+      }
+    };
+
+  };
+
 B2GPresenter.prototype.actionInvoked =
   function B2GPresenter_actionInvoked(aObject, aActionName) {
     return {
       type: this.type,
       details: {
         eventType: 'action',
         data: UtteranceGenerator.genForAction(aObject, aActionName)
       }
@@ -609,21 +657,21 @@ this.Presentation = { // jshint ignore:l
       for each (p in this.presenters)]; // jshint ignore:line
   },
 
   actionInvoked: function Presentation_actionInvoked(aObject, aActionName) {
     return [p.actionInvoked(aObject, aActionName) // jshint ignore:line
       for each (p in this.presenters)]; // jshint ignore:line
   },
 
-  textChanged: function Presentation_textChanged(aIsInserted, aStartOffset,
-                                    aLength, aText,
+  textChanged: function Presentation_textChanged(aAccessible, aIsInserted,
+                                    aStartOffset, aLength, aText,
                                     aModifiedText) {
-    return [p.textChanged(aIsInserted, aStartOffset, aLength, aText, // jshint ignore:line
-      aModifiedText) for each (p in this.presenters)]; // jshint ignore:line
+    return [p.textChanged(aAccessible, aIsInserted, aStartOffset, aLength, // jshint ignore:line
+      aText, aModifiedText) for each (p in this.presenters)]; // jshint ignore:line
   },
 
   textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd,
                                                       aOldStart, aOldEnd,
                                                       aIsFromUserInput) {
     return [p.textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd, // jshint ignore:line
       aIsFromUserInput) for each (p in this.presenters)]; // jshint ignore:line
   },
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -621,16 +621,25 @@ function ExpectedValueChange(aValue, aOp
   ExpectedPresent.call(this, {
     eventType: 'value-change',
     data: [aValue]
   }, null, aOptions);
 }
 
 ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype);
 
+function ExpectedTextChanged(aValue, aOptions) {
+  ExpectedPresent.call(this, {
+    eventType: 'text-change',
+    data: aValue
+  }, null, aOptions);
+}
+
+ExpectedTextChanged.prototype = Object.create(ExpectedPresent.prototype);
+
 function ExpectedEditState(aEditState, aOptions) {
   ExpectedMessage.call(this, 'AccessFu:Input', aOptions);
   this.json = aEditState;
 }
 
 ExpectedEditState.prototype = Object.create(ExpectedMessage.prototype);
 
 function ExpectedTextSelectionChanged(aStart, aEnd, aOptions) {
--- a/accessible/tests/mochitest/jsat/test_content_text.html
+++ b/accessible/tests/mochitest/jsat/test_content_text.html
@@ -4,16 +4,19 @@
   <title>Tests AccessFu content integration</title>
   <meta charset="utf-8" />
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js">
   </script>
   <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js">
+  </script>
+  <script type="application/javascript"
           src="chrome://mochikit/content/chrome-harness.js">
   </script>
 
   <script type="application/javascript" src="../common.js"></script>
   <script type="application/javascript" src="../browser.js"></script>
   <script type="application/javascript" src="../events.js"></script>
   <script type="application/javascript" src="../role.js"></script>
   <script type="application/javascript" src="../states.js"></script>
@@ -164,19 +167,108 @@
            new ExpectedCursorChange(
             [ 'So we don\'t get dessert?', {string: 'label'} ]),
            new ExpectedAnnouncement('navigating'),
            new ExpectedEditState({
             editing: false,
             multiline: false,
             atStart: true,
             atEnd: false
-           }, { focused: 'html' })]
+           }, { focused: 'html' })],
+
+          [ContentMessages.focusSelector('input'),
+           new ExpectedAnnouncement('editing'),
+           new ExpectedEditState({
+            editing: true,
+            multiline: false,
+            atStart: true,
+            atEnd: true
+           }),
+           new ExpectedCursorChange([{string: 'entry'}]),
+           new ExpectedTextSelectionChanged(0, 0)
+          ],
+          [function() {
+             SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 3);
+             typeKey('a')();
+           },
+           new ExpectedTextChanged('a'),
+           new ExpectedTextSelectionChanged(1, 1),
+          ],
+          [typeKey('b'),
+           new ExpectedTextChanged('b'),
+           new ExpectedTextSelectionChanged(2, 2),
+          ],
+          [typeKey('c'),
+           new ExpectedTextChanged('c'),
+           new ExpectedTextSelectionChanged(3, 3),
+          ],
+          [typeKey('d'),
+           new ExpectedTextChanged('d'),
+           new ExpectedTextSelectionChanged(4, 4),
+          ],
+          [typeKey(' '),
+           new ExpectedTextChanged(' abcd'),
+           new ExpectedTextSelectionChanged(5, 5),
+          ],
+          [typeKey('e'),
+           new ExpectedTextChanged('e'),
+           new ExpectedTextSelectionChanged(6, 6),
+          ],
+          [function() {
+             SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 2);
+             typeKey('a')();
+           },
+           new ExpectedTextChanged(''),
+           new ExpectedTextSelectionChanged(7, 7),
+          ],
+          [typeKey('d'),
+           new ExpectedTextChanged(''),
+           new ExpectedTextSelectionChanged(8, 8),
+          ],
+          [typeKey(' '),
+           new ExpectedTextChanged(' ead'),
+           new ExpectedTextSelectionChanged(9, 9),
+          ],
+          [function() {
+             SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 1);
+             typeKey('f')();
+           },
+           new ExpectedTextChanged('f'),
+           new ExpectedTextSelectionChanged(10, 10),
+          ],
+          [typeKey('g'),
+           new ExpectedTextChanged('g'),
+           new ExpectedTextSelectionChanged(11, 11),
+          ],
+          [typeKey(' '),
+           new ExpectedTextChanged(' '),
+           new ExpectedTextSelectionChanged(12, 12),
+          ],
+          [function() {
+             SpecialPowers.setIntPref(KEYBOARD_ECHO_SETTING, 0);
+             typeKey('f')();
+           },
+           new ExpectedTextChanged(''),
+           new ExpectedTextSelectionChanged(13, 13),
+          ],
+          [typeKey('g'),
+           new ExpectedTextChanged(''),
+           new ExpectedTextSelectionChanged(14, 14),
+          ],
+          [typeKey(' '),
+           new ExpectedTextChanged(''),
+           new ExpectedTextSelectionChanged(15, 15),
+          ],
         ]);
 
+      const KEYBOARD_ECHO_SETTING = 'accessibility.accessfu.keyboard_echo';
+      function typeKey(key) {
+        return function() { synthesizeKey(key, {}, currentTabWindow()); };
+      }
+
       addA11yLoadEvent(function() {
         textTest.start(function () {
           closeBrowserWindow();
           SimpleTest.finish();
         });
       }, doc.defaultView);
     }
 
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -792,16 +792,19 @@ pref("dom.disable_window_open_dialog_fea
 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);
+// Setting to change the verbosity of entered text (0 - none, 1 - characters,
+// 2 - words, 3 - both)
+pref("accessibility.accessfu.keyboard_echo", 3);
 
 // Enable hit-target fluffing
 pref("ui.touch.radius.enabled", true);
 pref("ui.touch.radius.leftmm", 3);
 pref("ui.touch.radius.topmm", 5);
 pref("ui.touch.radius.rightmm", 3);
 pref("ui.touch.radius.bottommm", 2);
 
@@ -998,22 +1001,21 @@ pref("apz.x_stationary_size_multiplier",
 pref("apz.y_stationary_size_multiplier", "1.8");
 pref("apz.enlarge_displayport_when_clipped", true);
 // Use "sticky" axis locking
 pref("apz.axis_lock.mode", 2);
 pref("apz.subframe.enabled", true);
 
 // Overscroll-related settings
 pref("apz.overscroll.enabled", true);
-pref("apz.overscroll.fling_friction", "0.05");
-pref("apz.overscroll.fling_stopped_threshold", "0.4");
 pref("apz.overscroll.stretch_factor", "0.5");
-pref("apz.overscroll.snap_back.spring_stiffness", "0.05");
-pref("apz.overscroll.snap_back.spring_friction", "0.1");
-pref("apz.overscroll.snap_back.mass", "100");
+pref("apz.overscroll.spring_stiffness", "0.001");
+pref("apz.overscroll.spring_friction", "0.015");
+pref("apz.overscroll.stop_distance_threshold", "5.0");
+pref("apz.overscroll.stop_velocity_threshold", "0.01");
 
 // This preference allows FirefoxOS apps (and content, I think) to force
 // the use of software (instead of hardware accelerated) 2D canvases by
 // creating a context like this:
 //
 //   canvas.getContext('2d', { willReadFrequently: true })
 //
 // Using a software canvas can save memory when JS calls getImageData()
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -86,16 +86,47 @@
         } catch (e) {
           // We probably tried to reload a URI that caused an exception to
           // occur;  e.g. a nonexistent file.
         }
 
         buttonEl.disabled = true;
       }
 
+      function toggleDisplay(node) {
+        toggle = {
+          '': 'block',
+          'none': 'block',
+          'block': 'none'
+        };
+        node.style.display = toggle[node.style.display];
+      }
+
+      function showCertificateErrorReporting() {
+        // Display error reporting UI
+        document.getElementById('certificateErrorReporting').style.display = 'block';
+
+        // Get the hostname and add it to the panel
+        document.getElementById('hostname').textContent = document.location.hostname;
+
+        // Register click handler for the certificateErrorReportingPanel
+        document.getElementById('showCertificateErrorReportingPanel')
+                .addEventListener('click', function togglePanelVisibility() {
+          var panel = document.getElementById('certificateErrorReportingPanel');
+          toggleDisplay(panel);
+        });
+      }
+
+
+      function sendErrorReport() {
+        var event = new CustomEvent("AboutNetErrorSendReport", {bubbles:true});
+
+        document.dispatchEvent(event);
+      }
+
       function initPage()
       {
         var err = getErrorCode();
 
         // if it's an unknown error or there's no title or description
         // defined, get the generic message
         var errTitle = document.getElementById("et_" + err);
         var errDesc  = document.getElementById("ed_" + err);
@@ -156,16 +187,47 @@
         }
 
         if (err == "cspFrameAncestorBlocked") {
           // Remove the "Try again" button for CSP frame ancestors violation, since it's
           // almost certainly useless. (Bug 553180)
           document.getElementById("errorTryAgain").style.display = "none";
         }
 
+        window.addEventListener("AboutNetErrorOptions", function(evt) {
+        // Pinning errors are of type nssFailure2 (don't ask me why)
+          if (getErrorCode() == "nssFailure2") {
+          // TODO: and the pref is set...
+            var options = JSON.parse(evt.detail);
+            if (options && options.enabled) {
+              var checkbox = document.getElementById('automaticallyReportInFuture');
+              showCertificateErrorReporting();
+              if (options.automatic) {
+                // set the checkbox
+                checkbox.checked = true;
+              }
+
+              checkbox.addEventListener('change', function(evt) {
+                  var event = new CustomEvent("AboutNetErrorSetAutomatic",
+                    {bubbles:true, detail:evt.target.checked});
+                  document.dispatchEvent(event);
+                }, false);
+
+              var reportBtn = document.getElementById('reportCertificateError');
+              var retryBtn = document.getElementById('reportCertificateErrorRetry');
+
+              reportBtn.addEventListener('click', sendErrorReport, false);
+              retryBtn.addEventListener('click', sendErrorReport, false);
+            }
+          }
+        }.bind(this), true, true);
+
+        var event = new CustomEvent("AboutNetErrorLoad", {bubbles:true});
+        document.dispatchEvent(event);
+
         if (err == "nssBadCert") {
           // Remove the "Try again" button for security exceptions, since it's
           // almost certainly useless.
           document.getElementById("errorTryAgain").style.display = "none";
           document.getElementById("errorPageContainer").setAttribute("class", "certerror");
           addDomainErrorLink();
         }
         else {
@@ -343,16 +405,17 @@
         <div id="errorLongDesc" />
 
         <!-- Override section - For ssl errors only.  Removed on init for other
              error types.  -->
         <div id="securityOverrideDiv">
           <a id="securityOverrideLink" href="javascript:showSecuritySection();" >&securityOverride.linkText;</a>
           <div id="securityOverrideContent" style="display: none;">&securityOverride.warningContent;</div>
         </div>
+
       </div>
 
       <!-- Retry Button -->
       <button id="errorTryAgain" autocomplete="off" onclick="retryThis(this);">&retry.label;</button>
       <script>
         // Only do autofocus if we're the toplevel frame; otherwise we
         // don't want to call attention to ourselves!  The key part is
         // that autofocus happens on insertion into the tree, so we
@@ -363,16 +426,38 @@
             var nextSibling = button.nextSibling;
             var parent = button.parentNode;
             parent.removeChild(button);
             button.setAttribute("autofocus", "true");
             parent.insertBefore(button, nextSibling);
         }
       </script>
 
+      <!-- UI for option to report certificate errors to Mozilla. Removed on
+           init for other error types .-->
+      <div id="certificateErrorReporting">
+        <a id="showCertificateErrorReportingPanel" href="#">&errorReporting.title;<span class="downArrow"> ▼</span></a>
+      </div>
+
+      <div id="certificateErrorReportingPanel">
+        <p>&errorReporting.longDesc;</p>
+        <p>
+          <input type="checkbox" id="automaticallyReportInFuture" />
+          <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label>
+        </p>
+        <!-- TODO add link to relevant page on sumo -->
+        <a href="https://support.mozilla.org/kb/certificate-pinning-reports" target="new">&errorReporting.learnMore;</a>
+        <span id="reportingState">
+          <button id="reportCertificateError">&errorReporting.report;</button>
+          <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
+          <span id="reportSendingMessage">&errorReporting.sending;</span>
+          <span id="reportSentMessage">&errorReporting.sent;</span>
+        </span>
+      </div>
+
     </div>
 
     <!--
     - Note: It is important to run the script this way, instead of using
     - an onload handler. This is because error pages are loaded as
     - LOAD_BACKGROUND, which means that onload handlers will not be executed.
     -->
     <script type="application/javascript">initPage();</script>
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -87,16 +87,18 @@ var FullScreen = {
       // The user may quit fullscreen during an animation
       this._cancelAnimation();
       gNavToolbox.style.marginTop = "";
       if (this._isChromeCollapsed)
         this.mouseoverToggle(true);
       // This is needed if they use the context menu to quit fullscreen
       this._isPopupOpen = false;
 
+      document.documentElement.removeAttribute("inDOMFullscreen");
+
       this.cleanup();
     }
   },
 
   exitDomFullScreen : function() {
     document.mozCancelFullScreen();
   },
 
@@ -151,19 +153,17 @@ var FullScreen = {
     let focusManager = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
     if (focusManager.activeWindow != window) {
       // The top-level window has lost focus since the request to enter
       // full-screen was made. Cancel full-screen.
       document.mozCancelFullScreen();
       return;
     }
 
-    // Ensure the sidebar is hidden.
-    if (!document.getElementById("sidebar-box").hidden)
-      toggleSidebar();
+    document.documentElement.setAttribute("inDOMFullscreen", true);
 
     if (gFindBarInitialized)
       gFindBar.close();
 
     this.showWarning(aOrigin);
 
     // Exit DOM full-screen mode upon open, close, or change tab.
     gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen);
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -251,19 +251,24 @@ toolbar[customizing] > .overflow-button 
 %ifdef XP_WIN
 #main-window[sizemode="maximized"] #titlebar-buttonbox {
   -moz-appearance: -moz-window-button-box-maximized;
 }
 %endif
 
 %endif
 
-#main-window[inFullscreen] #global-notificationbox,
-#main-window[inFullscreen] #high-priority-global-notificationbox {
-  visibility: collapse;
+#main-window[inDOMFullscreen] #sidebar-box,
+#main-window[inDOMFullscreen] #sidebar-splitter {
+  visibility: collapse;
+}
+
+#main-window[inFullscreen] #global-notificationbox,
+#main-window[inFullscreen] #high-priority-global-notificationbox {
+  visibility: collapse;
 }
 
 /* Rules to help integrate SDK widgets */
 toolbaritem[sdkstylewidget="true"] > toolbarbutton,
 toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe,
 toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-text {
   display: none;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1,15 +1,16 @@
 # -*- indent-tabs-mode: nil; js-indent-level: 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/.
 
 let Ci = Components.interfaces;
 let Cu = Components.utils;
+let Cc = Components.classes;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/NotificationDB.jsm");
 Cu.import("resource:///modules/RecentWindow.jsm");
 Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
                                   "resource:///modules/BrowserUITelemetry.jsm");
@@ -42,16 +43,19 @@ var gProxyFavIcon = null;
 var gLastValidURLStr = "";
 var gInPrintPreviewMode = false;
 var gContextMenu = null; // nsContextMenu instance
 var gMultiProcessBrowser =
   window.QueryInterface(Ci.nsIInterfaceRequestor)
         .getInterface(Ci.nsIWebNavigation)
         .QueryInterface(Ci.nsILoadContext)
         .useRemoteTabs;
+var gAppInfo = Cc["@mozilla.org/xre/app-info;1"]
+                  .getService(Ci.nsIXULAppInfo)
+                  .QueryInterface(Ci.nsIXULRuntime);
 
 #ifndef XP_MACOSX
 var gEditUIVisible = true;
 #endif
 
 [
   ["gBrowser",            "content"],
   ["gNavToolbox",         "navigator-toolbox"],
@@ -2412,23 +2416,27 @@ function PageProxyClickHandler(aEvent)
  * us via async messaging.
  */
 let BrowserOnClick = {
   init: function () {
     let mm = window.messageManager;
     mm.addMessageListener("Browser:CertExceptionError", this);
     mm.addMessageListener("Browser:SiteBlockedError", this);
     mm.addMessageListener("Browser:NetworkError", this);
+    mm.addMessageListener("Browser:SendSSLErrorReport", this);
+    mm.addMessageListener("Browser:SetSSLErrorReportAuto", this);
   },
 
   uninit: function () {
     let mm = window.messageManager;
     mm.removeMessageListener("Browser:CertExceptionError", this);
     mm.removeMessageListener("Browser:SiteBlockedError", this);
     mm.removeMessageListener("Browser:NetworkError", this);
+    mm.removeMessageListener("Browser:SendSSLErrorReport", this);
+    mm.removeMessageListener("Browser:SetSSLErrorReportAuto", this);
   },
 
   handleEvent: function (event) {
     if (!event.isTrusted || // Don't trust synthetic events
         event.button == 2) {
       return;
     }
 
@@ -2457,17 +2465,132 @@ let BrowserOnClick = {
       case "Browser:SiteBlockedError":
         this.onAboutBlocked(msg.data.elementId, msg.data.isMalware,
                             msg.data.isTopFrame, msg.data.location);
       break;
       case "Browser:NetworkError":
         // Reset network state, the error page will refresh on its own.
         Services.io.offline = false;
       break;
-    }
+      case "Browser:SendSSLErrorReport":
+        this.onSSLErrorReport(msg.target, msg.data.elementId,
+                              msg.data.documentURI,
+                              msg.data.location,
+                              msg.data.securityInfo);
+      break;
+      case "Browser:SetSSLErrorReportAuto":
+        Services.prefs.setBoolPref("security.ssl.errorReporting.automatic", msg.json.automatic);
+      break;
+    }
+  },
+
+  onSSLErrorReport: function(browser, elementId, documentURI, location, securityInfo) {
+    function showReportStatus(reportStatus) {
+      gBrowser.selectedBrowser
+          .messageManager
+          .sendAsyncMessage("Browser:SSLErrorReportStatus",
+                            {
+                              reportStatus: reportStatus,
+                              documentURI: documentURI
+                            });
+    }
+
+    if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
+      showReportStatus("error");
+      Cu.reportError("User requested certificate error report sending, but certificate error reporting is disabled");
+      return;
+    }
+
+    let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
+                           .getService(Ci.nsISerializationHelper);
+    let transportSecurityInfo = serhelper.deserializeObject(securityInfo);
+    transportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
+
+    if (transportSecurityInfo.failedCertChain == null) {
+      Cu.reportError("transportSecurityInfo didn't have a failedCertChain for a failedChannel");
+      return;
+    }
+
+    showReportStatus("activity");
+
+    /*
+     * Requested info for the report:
+     * - Domain of bad connection
+     * - Error type (e.g. Pinning, domain mismatch, etc)
+     * - Cert chain (at minimum, same data to distrust each cert in the
+     *   chain)
+     * - Request data (e.g. User Agent, IP, Timestamp)
+     *
+     * The request data should be added to the report by the receiving server.
+     */
+
+    // TODO: can we pull this in from pippki.js isntead of duplicating it
+    // here?
+    function getDERString(cert)
+    {
+      var length = {};
+      var derArray = cert.getRawDER(length);
+      var derString = '';
+      for (var i = 0; i < derArray.length; i++) {
+        derString += String.fromCharCode(derArray[i]);
+      }
+      return derString;
+    }
+
+    // Convert the nsIX509CertList into a format that can be parsed into
+    // JSON
+    let asciiCertChain = [];
+    let certs = transportSecurityInfo.failedCertChain.getEnumerator();
+    while (certs.hasMoreElements()) {
+      let cert = certs.getNext();
+      cert.QueryInterface(Ci.nsIX509Cert);
+      asciiCertChain.push(btoa(getDERString(cert)));
+    }
+
+    let report = {
+      hostname: location.hostname,
+      port: location.port,
+      timestamp: Math.round(Date.now() / 1000),
+      errorCode: transportSecurityInfo.errorCode,
+      failedCertChain: asciiCertChain,
+      userAgent: window.navigator.userAgent,
+      version: 1,
+      build: gAppInfo.appBuildID,
+      product: gAppInfo.name,
+      channel: Services.prefs.getCharPref("app.update.channel")
+    }
+
+    let reportURL = Services.prefs.getCharPref("security.ssl.errorReporting.url");
+
+    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+        .createInstance(Ci.nsIXMLHttpRequest);
+    try {
+      xhr.open("POST", reportURL);
+    } catch (e) {
+      Cu.reportError("xhr.open exception", e);
+      showReportStatus("error");
+    }
+
+    xhr.onerror = function (e) {
+      // error making request to reportURL
+      Cu.reportError("xhr onerror", e);
+      showReportStatus("error");
+    };
+
+    xhr.onload = function (event) {
+      if (xhr.status !== 201 && xhr.status !== 0) {
+        // request returned non-success status
+        Cu.reportError("xhr returned failure code", xhr.status);
+        showReportStatus("error");
+      } else {
+        showReportStatus("complete");
+      }
+    };
+
+    xhr.send(JSON.stringify(report));
   },
 
   onAboutCertError: function (browser, elementId, isTopFrame, location, sslStatusAsString) {
     let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
 
     switch (elementId) {
       case "exceptionDialogButton":
         if (isTopFrame) {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -673,17 +673,21 @@
            Should you need to add items to the toolbar here, make sure to also add them
            to the default placements of buttons in CustomizableUI.jsm, so the
            customization code doesn't get confused.
       -->
     <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
              aria-label="&navbarCmd.label;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="small"
+#ifdef MOZ_DEV_EDITION
+             defaultset="urlbar-container,search-container,developer-button,bookmarks-menu-button,downloads-button,home-button,loop-call-button"
+#else
              defaultset="urlbar-container,search-container,bookmarks-menu-button,downloads-button,home-button,loop-call-button"
+#endif
              customizationtarget="nav-bar-customization-target"
              overflowable="true"
              overflowbutton="nav-bar-overflow-button"
              overflowtarget="widget-overflow-list"
              overflowpanel="widget-overflow"
              context="toolbar-context-menu">
 
       <hbox id="nav-bar-customization-target" flex="1">
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -117,16 +117,123 @@ if (Services.appinfo.processType == Serv
   }
 
   Cc["@mozilla.org/eventlistenerservice;1"]
     .getService(Ci.nsIEventListenerService)
     .addSystemEventListener(global, "contextmenu", handleContentContextMenu, true);
 
 }
 
+let AboutNetErrorListener = {
+  init: function(chromeGlobal) {
+    chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
+    chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
+    chromeGlobal.addEventListener('AboutNetErrorSendReport', this, false, true);
+  },
+
+  get isAboutNetError() {
+    return content.document.documentURI.startsWith("about:neterror");
+  },
+
+  handleEvent: function(aEvent) {
+    if (!this.isAboutNetError) {
+      return;
+    }
+
+    switch (aEvent.type) {
+    case "AboutNetErrorLoad":
+      this.onPageLoad(aEvent);
+      break;
+    case "AboutNetErrorSetAutomatic":
+      this.onSetAutomatic(aEvent);
+      break;
+    case "AboutNetErrorSendReport":
+      this.onSendReport(aEvent);
+      break;
+    }
+  },
+
+  onPageLoad: function(evt) {
+    let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
+    content.dispatchEvent(new content.CustomEvent("AboutNetErrorOptions", {
+            detail: JSON.stringify({
+              enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
+            automatic: automatic
+            })
+          }
+    ));
+    if (automatic) {
+      this.onSendReport(evt);
+    }
+  },
+
+  onSetAutomatic: function(evt) {
+    sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
+        automatic: evt.detail
+      });
+  },
+
+  onSendReport: function(evt) {
+    let contentDoc = content.document;
+
+    let reportSendingMsg = contentDoc.getElementById("reportSendingMessage");
+    let reportSentMsg = contentDoc.getElementById("reportSentMessage");
+    let reportBtn = contentDoc.getElementById("reportCertificateError");
+    let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry");
+
+    addMessageListener("Browser:SSLErrorReportStatus", function(message) {
+      // show and hide bits - but only if this is a message for the right
+      // document - we'll compare on document URI
+      if (contentDoc.documentURI === message.data.documentURI) {
+        switch(message.data.reportStatus) {
+        case "activity":
+          // Hide the button that was just clicked
+          reportBtn.style.display = "none";
+          retryBtn.style.display = "none";
+          reportSentMsg.style.display = "none";
+          reportSendingMsg.style.display = "inline";
+          break;
+        case "error":
+          // show the retry button
+          retryBtn.style.display = "inline";
+          reportSendingMsg.style.display = "none";
+          break;
+        case "complete":
+          // Show a success indicator
+          reportSentMsg.style.display = "inline";
+          reportSendingMsg.style.display = "none";
+          break;
+        }
+      }
+    });
+
+
+    let failedChannel = docShell.failedChannel;
+    let location = contentDoc.location.href;
+
+    let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
+                     .getService(Ci.nsISerializationHelper);
+
+    let serializable =  docShell.failedChannel.securityInfo
+                                .QueryInterface(Ci.nsITransportSecurityInfo)
+                                .QueryInterface(Ci.nsISerializable);
+
+    let serializedSecurityInfo = serhelper.serializeToString(serializable);
+
+    sendAsyncMessage("Browser:SendSSLErrorReport", {
+        elementId: evt.target.id,
+        documentURI: contentDoc.documentURI,
+        location: contentDoc.location,
+        securityInfo: serializedSecurityInfo
+      });
+  }
+}
+
+AboutNetErrorListener.init(this);
+
 let AboutHomeListener = {
   init: function(chromeGlobal) {
     chromeGlobal.addEventListener('AboutHomeLoad', this, false, true);
   },
 
   get isAboutHome() {
     return content.document.documentURI.toLowerCase() == "about:home";
   },
new file mode 100644
--- /dev/null
+++ b/browser/base/content/docs/sslerrorreport/dataformat.rst
@@ -0,0 +1,46 @@
+.. _healthreport_dataformat:
+
+==============
+Payload Format
+==============
+
+An example report::
+
+  {
+    "timestamp":1413490449,
+    "errorCode":-16384,
+    "failedCertChain":[
+      ],
+    "userAgent":"Mozilla/5.0 (X11; Linux x86_64; rv:36.0) Gecko/20100101 Firefox/36.0",
+    "version":1,
+    "build":"20141022164419",
+    "product":"Firefox",
+    "channel":"default"
+  }
+
+Where the data represents the following:
+
+"timestamp"
+  The (local) time at which the report was generated. Seconds since 1 Jan 1970,
+  UTC.
+
+"errorCode"
+  The error code. This is the error code from certificate verification. Here's a small list of the most commonly-encountered errors:
+  https://wiki.mozilla.org/SecurityEngineering/x509Certs#Error_Codes_in_Firefox
+  In theory many of the errors from sslerr.h, secerr.h, and pkixnss.h could be encountered. We're starting with just MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE, which means that key pinning failed (i.e. there wasn't an intersection between the keys in any computed trusted certificate chain and the expected list of keys for the domain the user is attempting to connect to).
+
+"failedCertChain"
+  The certificate chain which caused the pinning violation (array of base64
+  encoded PEM)
+
+"user agent"
+  The user agent string of the browser sending the report
+
+"build"
+  The build ID
+
+"product"
+  The product name
+
+"channel"
+  The user's release channel
new file mode 100644
--- /dev/null
+++ b/browser/base/content/docs/sslerrorreport/index.rst
@@ -0,0 +1,15 @@
+.. _sslerrorreport
+
+===================
+SSL Error Reporting
+===================
+
+With the introduction of HPKP, it becomes useful to be able to capture data
+on pin violations. SSL Error Reporting is an opt-in mechanism to allow users
+to send data on such violations to mozilla.
+
+.. toctree::
+   :maxdepth: 1
+
+   dataformat
+   preferences
new file mode 100644
--- /dev/null
+++ b/browser/base/content/docs/sslerrorreport/preferences.rst
@@ -0,0 +1,23 @@
+.. _healthreport_preferences:
+
+===========
+Preferences
+===========
+
+The following preferences are used by SSL Error reporting:
+
+"security.ssl.errorReporting.enabled"
+  Should the SSL Error Reporting UI be shown on pin violations? Default
+  value: ``true``
+
+"security.ssl.errorReporting.url"
+  Where should SSL error reports be sent? Default value:
+  ``https://data.mozilla.com/submit/sslreports-stg``
+
+"security.ssl.errorReporting.automatic"
+  Should error reports be sent without user interaction. Default value:
+  ``false``. Note: this pref is overridden by the value of
+  ``security.ssl.errorReporting.enabled``
+  This is only set when specifically requested by the user. The user can set
+  this value (or unset it) by checking the "Automatically report errors in the
+  future" checkbox when about:neterror is displayed for SSL Errors.
--- a/browser/base/content/pageinfo/security.js
+++ b/browser/base/content/pageinfo/security.js
@@ -252,33 +252,25 @@ function securityOnLoad() {
   var msg1;
   var msg2;
 
   if (info.isBroken) {
     hdr = pkiBundle.getString("pageInfo_MixedContent");
     msg1 = pkiBundle.getString("pageInfo_Privacy_Mixed1");
     msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
   }
-  else if (info.encryptionStrength >= 90) {
-    hdr = pkiBundle.getFormattedString("pageInfo_StrongEncryptionWithBitsAndProtocol",
+  else if (info.encryptionStrength > 0) {
+    hdr = pkiBundle.getFormattedString("pageInfo_EncryptionWithBitsAndProtocol",
                                        [info.encryptionAlgorithm,
                                         info.encryptionStrength + "",
                                         info.version]);
-    msg1 = pkiBundle.getString("pageInfo_Privacy_Strong1");
-    msg2 = pkiBundle.getString("pageInfo_Privacy_Strong2");
+    msg1 = pkiBundle.getString("pageInfo_Privacy_Encrypted1");
+    msg2 = pkiBundle.getString("pageInfo_Privacy_Encrypted2");
     security._cert = info.cert;
   }
-  else if (info.encryptionStrength > 0) {
-    hdr  = pkiBundle.getFormattedString("pageInfo_WeakEncryptionWithBitsAndProtocol",
-                                        [info.encryptionAlgorithm,
-                                         info.encryptionStrength + "",
-                                         info.version]);
-    msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_Weak1", [info.hostName]);
-    msg2 = pkiBundle.getString("pageInfo_Privacy_Weak2");
-  }
   else {
     hdr = pkiBundle.getString("pageInfo_NoEncryption");
     if (info.hostName != null)
       msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]);
     else
       msg1 = pkiBundle.getString("pageInfo_Privacy_None3");
     msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
   }
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -5,16 +5,17 @@ support-files =
   alltabslistener.html
   app_bug575561.html
   app_subframe_bug575561.html
   authenticate.sjs
   aboutHome_content_script.js
   browser_bug479408_sample.html
   browser_bug678392-1.html
   browser_bug678392-2.html
+  browser_bug846489_content.js
   browser_bug970746.xhtml
   browser_fxa_oauth.html
   browser_registerProtocolHandler_notification.html
   browser_star_hsts.sjs
   browser_tab_dragdrop2_frame1.xul
   browser_web_channel.html
   bug592338.html
   bug792517-2.html
@@ -60,16 +61,17 @@ support-files =
   head.js
   healthreport_testRemoteCommands.html
   moz.png
   offlineQuotaNotification.cacheManifest
   offlineQuotaNotification.html
   page_style_sample.html
   parsingTestHelpers.jsm
   pinning_headers.sjs
+  pinning_reports.sjs
   popup_blocker.html
   print_postdata.sjs
   redirect_bug623155.sjs
   searchSuggestionEngine.sjs
   searchSuggestionEngine.xml
   test-mixedcontent-securityerrors.html
   test_bug435035.html
   test_bug462673.html
@@ -147,16 +149,17 @@ skip-if = e10s
 [browser_bug413915.js]
 [browser_bug416661.js]
 skip-if = e10s # Bug 691614 - no e10s zoom support yet
 [browser_bug417483.js]
 skip-if = e10s # Bug ?????? - no about:home support yet
 [browser_bug419612.js]
 skip-if = e10s # Bug 691614 - no e10s zoom support yet
 [browser_bug422590.js]
+[browser_bug846489.js]
 [browser_bug423833.js]
 skip-if = true # bug 428712
 [browser_bug424101.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content
 [browser_bug427559.js]
 skip-if = e10s # Bug ?????? - "content window is focused - Got [object ChromeWindow], expected [object XrayWrapper [object Window]]"
 [browser_bug431826.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (eg, var expertDiv = gBrowser.contentDocument.getElementById("expertContent");)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_bug846489.js
@@ -0,0 +1,327 @@
+var badPin = "https://include-subdomains.pinning.example.com";
+var enabledPref = false;
+var automaticPref = false;
+var urlPref = "security.ssl.errorReporting.url";
+var enforcement_level = 1;
+
+function loadFrameScript() {
+  let mm = Cc["@mozilla.org/globalmessagemanager;1"]
+           .getService(Ci.nsIMessageListenerManager);
+  const ROOT = getRootDirectory(gTestPath);
+  mm.loadFrameScript(ROOT+"browser_bug846489_content.js", true);
+}
+
+add_task(function*(){
+  waitForExplicitFinish();
+  loadFrameScript();
+  SimpleTest.requestCompleteLog();
+  yield testSendReportDisabled();
+  yield testSendReportManual();
+  yield testSendReportAuto();
+  yield testSendReportError();
+  yield testSetAutomatic();
+});
+
+// creates a promise of the message in an error page
+function createNetworkErrorMessagePromise(aBrowser) {
+  return new Promise(function(resolve, reject) {
+    // Error pages do not fire "load" events, so use a progressListener.
+    var originalDocumentURI = aBrowser.contentDocument.documentURI;
+
+    var progressListener = {
+      onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
+        // Make sure nothing other than an error page is loaded.
+        if (!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE)) {
+          reject("location change was not to an error page");
+        }
+      },
+
+      onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+        let doc = aBrowser.contentDocument;
+
+        if (doc.getElementById("reportCertificateError")) {
+          // Wait until the documentURI changes (from about:blank) this should
+          // be the error page URI.
+          var documentURI = doc.documentURI;
+          if (documentURI == originalDocumentURI) {
+            return;
+          }
+
+          aWebProgress.removeProgressListener(progressListener,
+            Ci.nsIWebProgress.NOTIFY_LOCATION |
+            Ci.nsIWebProgress.NOTIFY_STATE_REQUEST);
+          var matchArray = /about:neterror\?.*&d=([^&]*)/.exec(documentURI);
+          if (!matchArray) {
+            reject("no network error message found in URI")
+          return;
+          }
+
+          var errorMsg = matchArray[1];
+          resolve(decodeURIComponent(errorMsg));
+        }
+      },
+
+      QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                          Ci.nsISupportsWeakReference])
+    };
+
+    aBrowser.addProgressListener(progressListener,
+            Ci.nsIWebProgress.NOTIFY_LOCATION |
+            Ci.nsIWebProgress.NOTIFY_STATE_REQUEST);
+  });
+}
+
+// check we can set the 'automatically send' pref
+let testSetAutomatic = Task.async(function*() {
+  setup();
+  let tab = gBrowser.addTab(badPin, {skipAnimation: true});
+  let browser = tab.linkedBrowser;
+  let mm = browser.messageManager;
+
+  gBrowser.selectedTab = tab;
+
+  // ensure we have the correct error message from about:neterror
+  let netError = createNetworkErrorMessagePromise(browser);
+  yield netError;
+
+  //  ensure that setting automatic when unset works
+  let prefEnabled = new Promise(function(resolve, reject){
+    mm.addMessageListener("ssler-test:AutoPrefUpdated", function() {
+      if (Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
+        resolve();
+      } else {
+        reject();
+      }
+    });
+  });
+
+  mm.sendAsyncMessage("ssler-test:SetAutoPref",{value:true});
+
+  yield prefEnabled;
+
+  // ensure un-setting automatic, when set, works
+  let prefDisabled = new Promise(function(resolve, reject){
+    mm.addMessageListener("ssler-test:AutoPrefUpdated", function () {
+      if (!Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
+        resolve();
+      } else {
+        reject();
+      }
+    });
+  });
+
+  mm.sendAsyncMessage("ssler-test:SetAutoPref",{value:false});
+
+  yield prefDisabled;
+
+  gBrowser.removeTab(tab);
+  cleanup();
+});
+
+// test that manual report sending (with button clicks) works
+let testSendReportManual = Task.async(function*() {
+  setup();
+  Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
+  Services.prefs.setCharPref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/pinning_reports.sjs?succeed");
+
+  let tab = gBrowser.addTab(badPin, {skipAnimation: true});
+  let browser = tab.linkedBrowser;
+  let mm = browser.messageManager;
+
+  gBrowser.selectedTab = tab;
+
+  // ensure we have the correct error message from about:neterror
+  let netError = createNetworkErrorMessagePromise(browser);
+  yield netError;
+  netError.then(function(val){
+    is(val.startsWith("An error occurred during a connection to include-subdomains.pinning.example.com"), true ,"ensure the correct error message came from about:neterror");
+  });
+
+  // Check the report starts on click
+  let btn = browser.contentDocument.getElementById("reportCertificateError");
+
+  // check the content script sends the message to report
+  let reportWillStart = new Promise(function(resolve, reject){
+    mm.addMessageListener("Browser:SendSSLErrorReport", function() {
+      resolve();
+    });
+  });
+
+  let deferredReportActivity = Promise.defer()
+  let deferredReportSucceeds = Promise.defer();
+
+  // ensure we see the correct statuses in the correct order...
+  mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
+    switch(message.data.reportStatus) {
+      case "activity":
+        deferredReportActivity.resolve(message.data.reportStatus);
+        break;
+      case "complete":
+        deferredReportSucceeds.resolve(message.data.reportStatus);
+        break;
+      case "error":
+        deferredReportSucceeds.reject();
+        deferredReportActivity.reject();
+        break;
+    }
+  });
+
+  // ... once the button is clicked, that is
+  mm.sendAsyncMessage("ssler-test:SendBtnClick",{});
+
+  yield reportWillStart;
+
+  yield deferredReportActivity.promise;
+  yield deferredReportSucceeds.promise;
+
+  gBrowser.removeTab(tab);
+  cleanup();
+});
+
+// test that automatic sending works
+let testSendReportAuto = Task.async(function*() {
+  setup();
+  Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
+  Services.prefs.setBoolPref("security.ssl.errorReporting.automatic", true);
+  Services.prefs.setCharPref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/pinning_reports.sjs?succeed");
+
+  let tab = gBrowser.addTab(badPin, {skipAnimation: true});
+  let browser = tab.linkedBrowser;
+  let mm = browser.messageManager;
+
+  gBrowser.selectedTab = tab;
+
+  let reportWillStart = Promise.defer();
+  mm.addMessageListener("Browser:SendSSLErrorReport", function() {
+    reportWillStart.resolve();
+  });
+
+  let deferredReportActivity = Promise.defer();
+  let deferredReportSucceeds = Promise.defer();
+
+  mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
+    switch(message.data.reportStatus) {
+      case "activity":
+        deferredReportActivity.resolve(message.data.reportStatus);
+        break;
+      case "complete":
+        deferredReportSucceeds.resolve(message.data.reportStatus);
+        break;
+      case "error":
+        deferredReportSucceeds.reject();
+        deferredReportActivity.reject();
+        break;
+    }
+  });
+
+  // Ensure the error page loads
+  let netError = createNetworkErrorMessagePromise(browser);
+  yield netError;
+
+  // Ensure the reporting steps all occur with no interaction
+  yield reportWillStart;
+  yield deferredReportActivity.promise;
+  yield deferredReportSucceeds.promise;
+
+  gBrowser.removeTab(tab);
+  cleanup();
+});
+
+// test that an error is shown if there's a problem with the report server
+let testSendReportError = Task.async(function*() {
+  setup();
+  Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
+  Services.prefs.setBoolPref("security.ssl.errorReporting.automatic", true);
+  Services.prefs.setCharPref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/pinning_reports.sjs?error");
+
+  let tab = gBrowser.addTab(badPin, {skipAnimation: true});
+  let browser = tab.linkedBrowser;
+  let mm = browser.messageManager;
+
+  gBrowser.selectedTab = tab;
+
+  // check the report send starts....
+  let reportWillStart = new Promise(function(resolve, reject){
+    mm.addMessageListener("Browser:SendSSLErrorReport", function() {
+      resolve();
+    });
+  });
+
+  let netError = createNetworkErrorMessagePromise(browser);
+  yield netError;
+  yield reportWillStart;
+
+  // and that errors are seen
+  let reportErrors = new Promise(function(resolve, reject) {
+    mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
+      switch(message.data.reportStatus) {
+      case "complete":
+        reject(message.data.reportStatus);
+        break;
+      case "error":
+        resolve(message.data.reportStatus);
+        break;
+      }
+    });
+  });
+
+  yield reportErrors;
+
+  gBrowser.removeTab(tab);
+  cleanup();
+});
+
+let testSendReportDisabled = Task.async(function*() {
+  setup();
+  Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", false);
+  Services.prefs.setCharPref("security.ssl.errorReporting.url", "https://offdomain.com");
+
+  let tab = gBrowser.addTab(badPin, {skipAnimation: true});
+  let browser = tab.linkedBrowser;
+  let mm = browser.messageManager;
+
+  gBrowser.selectedTab = tab;
+
+  // Ensure we have an error page
+  let netError = createNetworkErrorMessagePromise(browser);
+  yield netError;
+
+  let reportErrors = new Promise(function(resolve, reject) {
+    mm.addMessageListener("ssler-test:SSLErrorReportStatus", function(message) {
+      switch(message.data.reportStatus) {
+      case "complete":
+        reject(message.data.reportStatus);
+        break;
+      case "error":
+        resolve(message.data.reportStatus);
+        break;
+      }
+    });
+  });
+
+  // click the button
+  mm.sendAsyncMessage("ssler-test:SendBtnClick",{forceUI:true});
+
+  // check we get an error
+  yield reportErrors;
+
+  gBrowser.removeTab(tab);
+  cleanup();
+});
+
+function setup() {
+  // ensure the relevant prefs are set
+  enabledPref = Services.prefs.getBoolPref("security.ssl.errorReporting.enabled");
+  automaticPref = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
+  urlPref = Services.prefs.getCharPref("security.ssl.errorReporting.url");
+
+  enforcement_level = Services.prefs.getIntPref("security.cert_pinning.enforcement_level");
+  Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
+}
+
+function cleanup() {
+  // reset prefs for other tests in the run
+  Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", enabledPref);
+  Services.prefs.setBoolPref("security.ssl.errorReporting.automatic", automaticPref);
+  Services.prefs.setCharPref("security.ssl.errorReporting.url", urlPref);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_bug846489_content.js
@@ -0,0 +1,25 @@
+addMessageListener("Browser:SSLErrorReportStatus", function(message) {
+  sendSyncMessage("ssler-test:SSLErrorReportStatus", {reportStatus:message.data.reportStatus});
+});
+
+addMessageListener("ssler-test:SetAutoPref", function(message) {
+  let checkbox = content.document.getElementById("automaticallyReportInFuture");
+
+  // we use "click" because otherwise the 'changed' event will not fire
+  if (checkbox.checked != message.data.value) {
+    checkbox.click();
+  }
+
+  sendSyncMessage("ssler-test:AutoPrefUpdated", {});
+});
+
+addMessageListener("ssler-test:SendBtnClick", function(message) {
+  if (message.data && message.data.forceUI) {
+    content.dispatchEvent(new content.CustomEvent("AboutNetErrorOptions",
+        {
+          detail: "{\"enabled\": true, \"automatic\": false}"
+        }));
+  }
+  let btn = content.document.getElementById("reportCertificateError");
+  btn.click();
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/pinning_reports.sjs
@@ -0,0 +1,41 @@
+const EXPECTED_CHAIN = [
+  "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"
+  ];
+
+function handleRequest(request, response)
+{
+  if (request.queryString === "succeed") {
+    // read the report from the client
+    let inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
+    inputStream.init(request.bodyInputStream, 0x01, 0004, 0);
+
+    let body = "";
+    if (inputStream) {
+      while (inputStream.available()) {
+        body = body + inputStream.read(inputStream.available());
+      }
+    }
+    // parse the report
+    let report = JSON.parse(body);
+    let certChain = report.failedCertChain;
+
+    // ensure the cert chain is what we expect
+    for (idx in certChain) {
+      if (certChain[idx] !== EXPECTED_CHAIN[idx]) {
+        // if the chain differs, send an error response to cause test
+        // failure
+        response.setStatusLine("1.1", 500, "Server error");
+        response.write("<html>The report contained an unexpected chain</html>");
+        return;
+      }
+    }
+
+    // if all is as expected, send the 201 the client expects
+    response.setStatusLine("1.1", 201, "Created");
+    response.write("<html>OK</html>");
+  } else if (request.queryString === "error") {
+    response.setStatusLine("1.1", 500, "Server error");
+    response.write("<html>server error</html>");
+  }
+}
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+SPHINX_TREES['sslerrorreport'] = 'content/docs/sslerrorreport'
+
 MOCHITEST_MANIFESTS += [
     'content/test/general/mochitest.ini',
 ]
 
 MOCHITEST_CHROME_MANIFESTS += [
     'content/test/chrome/chrome.ini',
 ]
 
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -170,17 +170,19 @@ let CustomizableUIInternal = {
       "privatebrowsing-button",
       "save-page-button",
       "print-button",
       "history-panelmenu",
       "fullscreen-button",
       "find-button",
       "preferences-button",
       "add-ons-button",
+#ifndef MOZ_DEV_EDITION
       "developer-button",
+#endif
     ];
 
     if (gPalette.has("switch-to-metro-button")) {
       panelPlacements.push("switch-to-metro-button");
     }
 
 #ifdef E10S_TESTING_ONLY
     if (gPalette.has("e10s-button")) {
@@ -204,16 +206,19 @@ let CustomizableUIInternal = {
       type: CustomizableUI.TYPE_MENU_PANEL,
       defaultPlacements: panelPlacements
     }, true);
     PanelWideWidgetTracker.init();
 
     let navbarPlacements = [
       "urlbar-container",
       "search-container",
+#ifdef MOZ_DEV_EDITION
+      "developer-button",
+#endif
       "bookmarks-menu-button",
       "downloads-button",
       "home-button",
       "loop-call-button",
     ];
 
     if (Services.prefs.getBoolPref(kPrefWebIDEInNavbar)) {
       navbarPlacements.push("webide-button");
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -338,17 +338,21 @@ const CustomizableWidgets = [
       }
     }
   }, {
     id: "developer-button",
     type: "view",
     viewId: "PanelUI-developer",
     shortcutId: "key_devToolboxMenuItem",
     tooltiptext: "developer-button.tooltiptext2",
+#ifdef MOZ_DEV_EDITION
+    defaultArea: CustomizableUI.AREA_NAVBAR,
+#else
     defaultArea: CustomizableUI.AREA_PANEL,
+#endif
     onViewShowing: function(aEvent) {
       // Populate the subview with whatever menuitems are in the developer
       // menu. We skip menu elements, because the menu panel has no way
       // of dealing with those right now.
       let doc = aEvent.target.ownerDocument;
       let win = doc.defaultView;
 
       let menu = doc.getElementById("menuWebDeveloperPopup");
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -1063,16 +1063,17 @@ CustomizeMode.prototype = {
       for (let target of this.areas) {
         for (let toolbarItem of target.children) {
           if (this.isWrappedToolbarItem(toolbarItem)) {
             yield this.deferredUnwrapToolbarItem(toolbarItem);
           }
         }
         this._removeDragHandlers(target);
       }
+      this.areas.clear();
     }.bind(this)).then(null, ERROR);
   },
 
   _removeExtraToolbarsIfEmpty: function() {
     let toolbox = this.window.gNavToolbox;
     for (let child of toolbox.children) {
       if (child.hasAttribute("customindex")) {
         let placements = CustomizableUI.getWidgetIdsInArea(child.id);
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -143,10 +143,14 @@ skip-if = e10s # Bug 1088710
 [browser_995164_registerArea_during_customize_mode.js]
 [browser_996364_registerArea_different_properties.js]
 [browser_996635_remove_non_widgets.js]
 [browser_1003588_no_specials_in_panel.js]
 [browser_1007336_lwthemes_in_customize_mode.js]
 [browser_1008559_anchor_undo_restore.js]
 [browser_1042100_default_placements_update.js]
 [browser_1058573_showToolbarsDropdown.js]
+[browser_1087303_button_fullscreen.js]
+skip-if = os == "mac"
+[browser_1087303_button_preferences.js]
 [browser_bootstrapped_custom_toolbar.js]
 [browser_panel_toggle.js]
+[browser_1089591_still_customizable_after_reset.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_1087303_button_fullscreen.js
@@ -0,0 +1,46 @@
+/* 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/. */
+
+"use strict";
+
+add_task(function() {
+  info("Check fullscreen button existence and functionality");
+
+  yield PanelUI.show();
+
+  let fullscreenButton = document.getElementById("fullscreen-button");
+  ok(fullscreenButton, "Fullscreen button appears in Panel Menu");
+
+  let fullscreenPromise = promiseFullscreenChange();
+  fullscreenButton.click();
+  yield fullscreenPromise;
+
+  ok(window.fullScreen, "Fullscreen mode was opened");
+
+  // exit full screen mode
+  fullscreenPromise = promiseFullscreenChange();
+  window.fullScreen = !window.fullScreen;
+  yield fullscreenPromise;
+
+  ok(!window.fullScreen, "Successfully exited fullscreen");
+});
+
+function promiseFullscreenChange() {
+  let deferred = Promise.defer();
+  info("Wait for fullscreen change");
+
+  let timeoutId = setTimeout(() => {
+    window.removeEventListener("fullscreen", onFullscreenChange, true);
+    deferred.reject("Fullscreen change did not happen within " + 20000 + "ms");
+  }, 20000);
+
+  function onFullscreenChange(event) {
+    clearTimeout(timeoutId);
+    window.removeEventListener("fullscreen", onFullscreenChange, true);
+    info("Fullscreen event received");
+    deferred.resolve();
+  }
+  window.addEventListener("fullscreen", onFullscreenChange, true);
+  return deferred.promise;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_1087303_button_preferences.js
@@ -0,0 +1,57 @@
+/* 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/. */
+
+"use strict";
+
+const PREF_INCONTENT = "browser.preferences.inContent";
+
+let newTab = null;
+
+add_task(function() {
+  info("Check preferences button existence and functionality");
+
+  Services.prefs.setBoolPref(PREF_INCONTENT, true);
+
+  yield PanelUI.show();
+  info("Menu panel was opened");
+
+  let preferencesButton = document.getElementById("preferences-button");
+  ok(preferencesButton, "Preferences button exists in Panel Menu");
+  preferencesButton.click();
+
+  newTab = gBrowser.selectedTab;
+  yield waitForPageLoad(newTab);
+
+  let openedPage = gBrowser.currentURI.spec;
+  is(openedPage, "about:preferences", "Preferences page was opened");
+});
+
+add_task(function asyncCleanup() {
+  if (gBrowser.tabs.length == 1)
+    gBrowser.addTab("about:blank");
+
+  gBrowser.removeTab(gBrowser.selectedTab);
+  info("Tabs were restored");
+
+  // restore the browser.preferences.inContent preference
+  Services.prefs.clearUserPref(PREF_INCONTENT);
+});
+
+function waitForPageLoad(aTab) {
+  let deferred = Promise.defer();
+
+  let timeoutId = setTimeout(() => {
+    aTab.linkedBrowser.removeEventListener("load", onTabLoad, true);
+    deferred.reject("Page didn't load within " + 20000 + "ms");
+  }, 20000);
+
+  function onTabLoad(event) {
+    clearTimeout(timeoutId);
+    aTab.linkedBrowser.removeEventListener("load", onTabLoad, true);
+    info("Tab event received: " + "load");
+    deferred.resolve();
+ }
+  aTab.linkedBrowser.addEventListener("load", onTabLoad, true, true);
+  return deferred.promise;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_1089591_still_customizable_after_reset.js
@@ -0,0 +1,25 @@
+"use strict";
+
+// Dragging the elements again after a reset should work
+add_task(function* () {
+  yield startCustomizing();
+  let historyButton = document.getElementById("wrapper-history-panelmenu");
+  let devButton = document.getElementById("wrapper-developer-button");
+
+  ok(historyButton && devButton, "Draggable elements should exist");
+  simulateItemDrag(historyButton, devButton);
+  gCustomizeMode.reset();
+  yield waitForCondition(() => !gCustomizeMode.resetting);
+  ok(CustomizableUI.inDefaultState, "Should be back in default state");
+
+  historyButton = document.getElementById("wrapper-history-panelmenu");
+  devButton = document.getElementById("wrapper-developer-button");
+  ok(historyButton && devButton, "Draggable elements should exist");
+  simulateItemDrag(historyButton, devButton);
+
+  yield endCustomizing();
+});
+
+add_task(function* asyncCleanup() {
+  yield resetCustomization();
+});
--- a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
+++ b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
@@ -18,16 +18,17 @@ add_task(function() {
                              "zoom-controls",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(zoomControls, printButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let newWindowButton = document.getElementById("new-window-button");
   simulateItemDrag(zoomControls, newWindowButton);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
@@ -44,16 +45,17 @@ add_task(function() {
                              "save-page-button",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(zoomControls, savePageButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(CustomizableUI.inDefaultState, "Should be in default state.");
 });
 
 
 // Dragging the zoom controls to be before the new-window button should not move any widgets.
@@ -68,16 +70,17 @@ add_task(function() {
                              "save-page-button",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(zoomControls, newWindowButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the zoom controls to be before the history-panelmenu should move the zoom-controls in to the row higher than the history-panelmenu.
 add_task(function() {
@@ -91,16 +94,17 @@ add_task(function() {
                              "zoom-controls",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(zoomControls, historyPanelMenu);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let newWindowButton = document.getElementById("new-window-button");
   simulateItemDrag(zoomControls, newWindowButton);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
@@ -118,16 +122,17 @@ add_task(function() {
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "zoom-controls",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(zoomControls, preferencesButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let newWindowButton = document.getElementById("new-window-button");
   simulateItemDrag(zoomControls, newWindowButton);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
@@ -145,16 +150,17 @@ add_task(function() {
                                "save-page-button",
                                "print-button",
                                "history-panelmenu",
                                "fullscreen-button",
                                "find-button",
                                "preferences-button",
                                "add-ons-button",
                                "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterInsert);
   addSwitchToMetroButtonInWindows8(placementsAfterInsert);
   simulateItemDrag(openFileButton, zoomControls);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let palette = document.getElementById("customization-palette");
   // Check that the palette items are re-wrapped correctly.
   let feedWrapper = document.getElementById("wrapper-feed-button");
   let feedButton = document.getElementById("feed-button");
@@ -184,16 +190,17 @@ add_task(function() {
                                "save-page-button",
                                "print-button",
                                "history-panelmenu",
                                "fullscreen-button",
                                "find-button",
                                "preferences-button",
                                "add-ons-button",
                                "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterInsert);
   addSwitchToMetroButtonInWindows8(placementsAfterInsert);
   simulateItemDrag(openFileButton, editControls);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let palette = document.getElementById("customization-palette");
   // Check that the palette items are re-wrapped correctly.
   let feedWrapper = document.getElementById("wrapper-feed-button");
   let feedButton = document.getElementById("feed-button");
@@ -220,16 +227,17 @@ add_task(function() {
                              "save-page-button",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(editControls, zoomControls);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the edit-controls to be before the new-window-button should
 // move the zoom-controls before the edit-controls.
@@ -244,16 +252,17 @@ add_task(function() {
                              "save-page-button",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(editControls, newWindowButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
@@ -271,16 +280,17 @@ add_task(function() {
                              "save-page-button",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(editControls, privateBrowsingButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
@@ -298,16 +308,17 @@ add_task(function() {
                              "save-page-button",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(editControls, savePageButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
@@ -324,16 +335,17 @@ add_task(function() {
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "edit-controls",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(editControls, panel);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
@@ -349,16 +361,17 @@ add_task(function() {
                              "save-page-button",
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   let paletteChildElementCount = palette.childElementCount;
   simulateItemDrag(editControls, palette);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   is(paletteChildElementCount + 1, palette.childElementCount,
      "The palette should have a new child, congratulations!");
   is(editControls.parentNode.id, "wrapper-edit-controls",
      "The edit-controls should be properly wrapped.");
@@ -389,16 +402,17 @@ add_task(function() {
                                "print-button",
                                "history-panelmenu",
                                "fullscreen-button",
                                "find-button",
                                "preferences-button",
                                "add-ons-button",
                                "edit-controls",
                                "developer-button"];
+    removeDeveloperButtonIfDevEdition(placementsAfterMove);
     addSwitchToMetroButtonInWindows8(placementsAfterMove);
     simulateItemDrag(editControls, placeholder);
     assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
     let zoomControls = document.getElementById("zoom-controls");
     simulateItemDrag(editControls, zoomControls);
     ok(CustomizableUI.inDefaultState, "Should still be in default state.");
   }
 });
@@ -431,16 +445,17 @@ add_task(function() {
                              "print-button",
                              "history-panelmenu",
                              "fullscreen-button",
                              "find-button",
                              "preferences-button",
                              "add-ons-button",
                              "edit-controls",
                              "developer-button"];
+  removeDeveloperButtonIfDevEdition(placementsAfterMove);
   addSwitchToMetroButtonInWindows8(placementsAfterMove);
   simulateItemDrag(editControls, target);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   let itemToDrag = "sync-button";
   let button = document.getElementById(itemToDrag);
   placementsAfterMove.splice(11, 0, itemToDrag);
   if (isInWin8()) {
     placementsAfterMove[10] = placementsAfterMove[11];
--- a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
+++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
@@ -4,76 +4,106 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // One orphaned item should have two placeholders next to it.
 add_task(function() {
   yield startCustomizing();
-  let btn = document.getElementById("open-file-button");
-  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
   if (isInWin8()) {
     CustomizableUI.removeWidgetFromArea("switch-to-metro-button");
-    placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
     ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+  }
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
+    ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+  }
+  if (!isInWin8() && !isInDevEdition()) {
+    ok(CustomizableUI.inDefaultState, "Should be in default state.");
   } else {
-    ok(CustomizableUI.inDefaultState, "Should be in default state.");
+    ok(!CustomizableUI.inDefaultState, "Should not be in default state if on Win8 or DevEdition.");
   }
 
+  let btn = document.getElementById("open-file-button");
+  let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+  let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
   is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting");
 
   yield endCustomizing();
   yield startCustomizing();
   is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering");
 
   if (isInWin8()) {
     CustomizableUI.addWidgetToArea("switch-to-metro-button", CustomizableUI.AREA_PANEL);
   }
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
+  }
+
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Two orphaned items should have one placeholder next to them (case 1).
 add_task(function() {
   yield startCustomizing();
+
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
+  }
+
   let btn = document.getElementById("open-file-button");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
-
   let placementsAfterAppend = placements;
 
   if (!isInWin8()) {
     placementsAfterAppend = placements.concat(["open-file-button"]);
     simulateItemDrag(btn, panel);
   }
 
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
-  is(CustomizableUI.inDefaultState, isInWin8(), "Should only be in default state if on Win8");
+
+  if (isInWin8() && !isInDevEdition()) {
+    ok(CustomizableUI.inDefaultState, "Should be in default state if on Win8 and not on DevEdition.");
+  } else {
+    ok(!CustomizableUI.inDefaultState, "Should not be in default state if not Win8 or on DevEdition.");
+  }
+
   is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder before exiting");
 
   yield endCustomizing();
   yield startCustomizing();
   is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder after re-entering");
 
   let palette = document.getElementById("customization-palette");
   simulateItemDrag(btn, palette);
 
   if (!isInWin8()) {
     btn = document.getElementById("open-file-button");
     simulateItemDrag(btn, palette);
   }
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
+  }
+
   ok(CustomizableUI.inDefaultState, "Should be in default state again."); 
 });
 
 // Two orphaned items should have one placeholder next to them (case 2).
 add_task(function() {
   yield startCustomizing();
+
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
+  }
+
   let btn = document.getElementById("add-ons-button");
   let btn2 = document.getElementById("developer-button");
   let btn3 = document.getElementById("switch-to-metro-button");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let palette = document.getElementById("customization-palette");
   let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
   let placementsAfterAppend = placements.filter(p => p != btn.id && p != btn2.id);
@@ -96,60 +126,93 @@ add_task(function() {
   simulateItemDrag(btn, panel);
   simulateItemDrag(btn2, panel);
 
   if (isInWin8()) {
     simulateItemDrag(btn3, panel);
   }
 
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
+
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
+  }
+
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // A wide widget at the bottom of the panel should have three placeholders after it.
 add_task(function() {
   yield startCustomizing();
+
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
+  }
+
   let btn = document.getElementById("edit-controls");
-  let developerButton = document.getElementById("developer-button");
-  let metroBtn = document.getElementById("switch-to-metro-button");
+  let btn2 = document.getElementById("developer-button");
+  let btn3 = document.getElementById("switch-to-metro-button");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let palette = document.getElementById("customization-palette");
   let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
   placements.pop();
-  simulateItemDrag(developerButton, palette);
+  simulateItemDrag(btn2, palette);
+
   if (isInWin8()) {
     // Remove switch-to-metro-button
     placements.pop();
-    simulateItemDrag(metroBtn, palette);
+    simulateItemDrag(btn3, palette);
   }
 
   let placementsAfterAppend = placements.concat([placements.shift()]);
   simulateItemDrag(btn, panel);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting");
 
   yield endCustomizing();
   yield startCustomizing();
   is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
 
-  simulateItemDrag(developerButton, panel);
+  simulateItemDrag(btn2, panel);
+
   if (isInWin8()) {
-    simulateItemDrag(metroBtn, panel);
+    simulateItemDrag(btn3, panel);
   }
+
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(btn, zoomControls);
+
+  if (isInDevEdition()) {
+    CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
+  }
+
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // The default placements should have two placeholders at the bottom (or 1 in win8).
 add_task(function() {
   yield startCustomizing();
-  let numPlaceholders = isInWin8() ? 1 : 2;
+  let numPlaceholders = -1;
+
+  if (isInWin8()) {
+    if (isInDevEdition()) {
+      numPlaceholders = 2;
+    } else {
+      numPlaceholders = 1;
+    }
+  } else {
+    if (isInDevEdition()) {
+      numPlaceholders = 3;
+    } else {
+      numPlaceholders = 2;
+    }
+  }
+
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   ok(CustomizableUI.inDefaultState, "Should be in default state.");
   is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting");
 
   yield endCustomizing();
   yield startCustomizing();
   is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders after re-entering");
 
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -108,16 +108,30 @@ function removeCustomToolbars() {
 function getToolboxCustomToolbarId(toolbarName) {
   return "__customToolbar_" + toolbarName.replace(" ", "_");
 }
 
 function resetCustomization() {
   return CustomizableUI.reset();
 }
 
+XPCOMUtils.defineLazyGetter(this, 'gDeveloperButtonInNavbar', function() {
+  return getAreaWidgetIds(CustomizableUI.AREA_NAVBAR).indexOf("developer-button") != -1;
+});
+
+function isInDevEdition() {
+  return gDeveloperButtonInNavbar;
+}
+
+function removeDeveloperButtonIfDevEdition(areaPanelPlacements) {
+  if (isInDevEdition()) {
+    areaPanelPlacements.splice(areaPanelPlacements.indexOf("developer-button"), 1);
+  }
+}
+
 function isInWin8() {
   if (!Services.metro)
     return false;
   return Services.metro.supported;
 }
 
 function addSwitchToMetroButtonInWindows8(areaPanelPlacements) {
   if (isInWin8()) {
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -492,17 +492,17 @@ loop.panel = (function(_, mozL10n) {
     },
 
     handleMouseLeave: function(event) {
       this.setState({urlCopied: false});
     },
 
     _isActive: function() {
       // XXX bug 1074679 will implement this properly
-      return this.props.room.currSize > 0;
+      return this.props.room.participants.length > 0;
     },
 
     render: function() {
       var room = this.props.room;
       var roomClasses = React.addons.classSet({
         "room-entry": true,
         "room-active": this._isActive()
       });
@@ -533,67 +533,84 @@ loop.panel = (function(_, mozL10n) {
    * Room list.
    */
   var RoomList = React.createClass({displayName: 'RoomList',
     mixins: [Backbone.Events],
 
     propTypes: {
       store: React.PropTypes.instanceOf(loop.store.RoomListStore).isRequired,
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
-      rooms: React.PropTypes.array
+      userDisplayName: React.PropTypes.string.isRequired  // for room creation
     },
 
     getInitialState: function() {
-      var storeState = this.props.store.getStoreState();
-      return {
-        error: this.props.error || storeState.error,
-        rooms: this.props.rooms || storeState.rooms,
-      };
+      return this.props.store.getStoreState();
     },
 
-    componentWillMount: function() {
-      this.listenTo(this.props.store, "change", this._onRoomListChanged);
+    componentDidMount: function() {
+      this.listenTo(this.props.store, "change", this._onStoreStateChanged);
 
+      // XXX this should no longer be necessary once have a better mechanism
+      // for updating the list (possibly as part of the content side of bug
+      // 1074665.
       this.props.dispatcher.dispatch(new sharedActions.GetAllRooms());
     },
 
     componentWillUnmount: function() {
       this.stopListening(this.props.store);
     },
 
-    _onRoomListChanged: function() {
+    _onStoreStateChanged: function() {
       this.setState(this.props.store.getStoreState());
     },
 
     _getListHeading: function() {
       var numRooms = this.state.rooms.length;
       if (numRooms === 0) {
         return mozL10n.get("rooms_list_no_current_conversations");
       }
       return mozL10n.get("rooms_list_current_conversations", {num: numRooms});
     },
 
+    _hasPendingOperation: function() {
+      return this.state.pendingCreation || this.state.pendingInitialRetrieval;
+    },
+
+    handleCreateButtonClick: function() {
+      this.props.dispatcher.dispatch(new sharedActions.CreateRoom({
+        nameTemplate: mozL10n.get("rooms_default_room_name_template"),
+        roomOwner: this.props.userDisplayName
+      }));
+    },
+
     openRoom: function(room) {
       // XXX implement me; see bug 1074678
     },
 
     render: function() {
       if (this.state.error) {
         // XXX Better end user reporting of errors.
-        console.error(this.state.error);
+        console.error("RoomList error", this.state.error);
       }
 
       return (
-        React.DOM.div({className: "room-list"}, 
+        React.DOM.div({className: "rooms"}, 
           React.DOM.h1(null, this._getListHeading()), 
-          
+          React.DOM.div({className: "room-list"}, 
             this.state.rooms.map(function(room, i) {
               return RoomEntry({key: i, room: room, openRoom: this.openRoom});
             }, this)
-          
+          ), 
+          React.DOM.p(null, 
+            React.DOM.button({className: "btn btn-info", 
+                    onClick: this.handleCreateButtonClick, 
+                    disabled: this._hasPendingOperation()}, 
+              mozL10n.get("rooms_new_room_button_label")
+            )
+          )
         )
       );
     }
   });
 
   /**
    * Panel view.
    */
@@ -662,17 +679,18 @@ loop.panel = (function(_, mozL10n) {
      */
     _renderRoomsTab: function() {
       if (!navigator.mozLoop.getLoopBoolPref("rooms.enabled")) {
         return null;
       }
       return (
         Tab({name: "rooms"}, 
           RoomList({dispatcher: this.props.dispatcher, 
-                    store: this.props.roomListStore})
+                    store: this.props.roomListStore, 
+                    userDisplayName: this._getUserDisplayName()})
         )
       );
     },
 
     startForm: function(name, contact) {
       this.refs[name].initForm(contact);
       this.selectTab(name);
     },
@@ -688,20 +706,23 @@ loop.panel = (function(_, mozL10n) {
     componentDidMount: function() {
       window.addEventListener("LoopStatusChanged", this._onStatusChanged);
     },
 
     componentWillUnmount: function() {
       window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
     },
 
+    _getUserDisplayName: function() {
+      return this.state.userProfile && this.state.userProfile.email ||
+             __("display_name_guest");
+    },
+
     render: function() {
       var NotificationListView = sharedViews.NotificationListView;
-      var displayName = this.state.userProfile && this.state.userProfile.email ||
-                        __("display_name_guest");
       return (
         React.DOM.div(null, 
           NotificationListView({notifications: this.props.notifications, 
                                 clearOnDocumentHidden: true}), 
           TabView({ref: "tabView", selectedTab: this.props.selectedTab, 
             buttonsHidden: !this.state.userProfile && !this.props.showTabButtons}, 
             Tab({name: "call"}, 
               React.DOM.div({className: "content-area"}, 
@@ -726,17 +747,17 @@ loop.panel = (function(_, mozL10n) {
             ), 
             Tab({name: "contacts_import", hidden: true}, 
               ContactDetailsForm({ref: "contacts_import", mode: "import", 
                                   selectTab: this.selectTab})
             )
           ), 
           React.DOM.div({className: "footer"}, 
             React.DOM.div({className: "user-details"}, 
-              UserIdentity({displayName: displayName}), 
+              UserIdentity({displayName: this._getUserDisplayName()}), 
               AvailabilityDropdown(null)
             ), 
             React.DOM.div({className: "signin-details"}, 
               AuthLink(null), 
               React.DOM.div({className: "footer-signin-separator"}), 
               SettingsDropdown(null)
             )
           )
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -492,17 +492,17 @@ loop.panel = (function(_, mozL10n) {
     },
 
     handleMouseLeave: function(event) {
       this.setState({urlCopied: false});
     },
 
     _isActive: function() {
       // XXX bug 1074679 will implement this properly
-      return this.props.room.currSize > 0;
+      return this.props.room.participants.length > 0;
     },
 
     render: function() {
       var room = this.props.room;
       var roomClasses = React.addons.classSet({
         "room-entry": true,
         "room-active": this._isActive()
       });
@@ -533,67 +533,84 @@ loop.panel = (function(_, mozL10n) {
    * Room list.
    */
   var RoomList = React.createClass({
     mixins: [Backbone.Events],
 
     propTypes: {
       store: React.PropTypes.instanceOf(loop.store.RoomListStore).isRequired,
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
-      rooms: React.PropTypes.array
+      userDisplayName: React.PropTypes.string.isRequired  // for room creation
     },
 
     getInitialState: function() {
-      var storeState = this.props.store.getStoreState();
-      return {
-        error: this.props.error || storeState.error,
-        rooms: this.props.rooms || storeState.rooms,
-      };
+      return this.props.store.getStoreState();
     },
 
-    componentWillMount: function() {
-      this.listenTo(this.props.store, "change", this._onRoomListChanged);
+    componentDidMount: function() {
+      this.listenTo(this.props.store, "change", this._onStoreStateChanged);
 
+      // XXX this should no longer be necessary once have a better mechanism
+      // for updating the list (possibly as part of the content side of bug
+      // 1074665.
       this.props.dispatcher.dispatch(new sharedActions.GetAllRooms());
     },
 
     componentWillUnmount: function() {
       this.stopListening(this.props.store);
     },
 
-    _onRoomListChanged: function() {
+    _onStoreStateChanged: function() {
       this.setState(this.props.store.getStoreState());
     },
 
     _getListHeading: function() {
       var numRooms = this.state.rooms.length;
       if (numRooms === 0) {
         return mozL10n.get("rooms_list_no_current_conversations");
       }
       return mozL10n.get("rooms_list_current_conversations", {num: numRooms});
     },
 
+    _hasPendingOperation: function() {
+      return this.state.pendingCreation || this.state.pendingInitialRetrieval;
+    },
+
+    handleCreateButtonClick: function() {
+      this.props.dispatcher.dispatch(new sharedActions.CreateRoom({
+        nameTemplate: mozL10n.get("rooms_default_room_name_template"),
+        roomOwner: this.props.userDisplayName
+      }));
+    },
+
     openRoom: function(room) {
       // XXX implement me; see bug 1074678
     },
 
     render: function() {
       if (this.state.error) {
         // XXX Better end user reporting of errors.
-        console.error(this.state.error);
+        console.error("RoomList error", this.state.error);
       }
 
       return (
-        <div className="room-list">
+        <div className="rooms">
           <h1>{this._getListHeading()}</h1>
-          {
+          <div className="room-list">{
             this.state.rooms.map(function(room, i) {
               return <RoomEntry key={i} room={room} openRoom={this.openRoom} />;
             }, this)
-          }
+          }</div>
+          <p>
+            <button className="btn btn-info"
+                    onClick={this.handleCreateButtonClick}
+                    disabled={this._hasPendingOperation()}>
+              {mozL10n.get("rooms_new_room_button_label")}
+            </button>
+          </p>
         </div>
       );
     }
   });
 
   /**
    * Panel view.
    */
@@ -662,17 +679,18 @@ loop.panel = (function(_, mozL10n) {
      */
     _renderRoomsTab: function() {
       if (!navigator.mozLoop.getLoopBoolPref("rooms.enabled")) {
         return null;
       }
       return (
         <Tab name="rooms">
           <RoomList dispatcher={this.props.dispatcher}
-                    store={this.props.roomListStore} />
+                    store={this.props.roomListStore}
+                    userDisplayName={this._getUserDisplayName()}/>
         </Tab>
       );
     },
 
     startForm: function(name, contact) {
       this.refs[name].initForm(contact);
       this.selectTab(name);
     },
@@ -688,20 +706,23 @@ loop.panel = (function(_, mozL10n) {
     componentDidMount: function() {
       window.addEventListener("LoopStatusChanged", this._onStatusChanged);
     },
 
     componentWillUnmount: function() {
       window.removeEventListener("LoopStatusChanged", this._onStatusChanged);
     },
 
+    _getUserDisplayName: function() {
+      return this.state.userProfile && this.state.userProfile.email ||
+             __("display_name_guest");
+    },
+
     render: function() {
       var NotificationListView = sharedViews.NotificationListView;
-      var displayName = this.state.userProfile && this.state.userProfile.email ||
-                        __("display_name_guest");
       return (
         <div>
           <NotificationListView notifications={this.props.notifications}
                                 clearOnDocumentHidden={true} />
           <TabView ref="tabView" selectedTab={this.props.selectedTab}
             buttonsHidden={!this.state.userProfile && !this.props.showTabButtons}>
             <Tab name="call">
               <div className="content-area">
@@ -726,17 +747,17 @@ loop.panel = (function(_, mozL10n) {
             </Tab>
             <Tab name="contacts_import" hidden={true}>
               <ContactDetailsForm ref="contacts_import" mode="import"
                                   selectTab={this.selectTab}/>
             </Tab>
           </TabView>
           <div className="footer">
             <div className="user-details">
-              <UserIdentity displayName={displayName} />
+              <UserIdentity displayName={this._getUserDisplayName()} />
               <AvailabilityDropdown />
             </div>
             <div className="signin-details">
               <AuthLink />
               <div className="footer-signin-separator" />
               <SettingsDropdown />
             </div>
           </div>
--- a/browser/components/loop/content/shared/css/panel.css
+++ b/browser/components/loop/content/shared/css/panel.css
@@ -134,27 +134,47 @@ body {
 }
 
 .content-area input:not(.pristine):invalid {
   border-color: #d74345;
   box-shadow: 0 0 4px #c43c3e;
 }
 
 /* Rooms */
-.room-list {
+.rooms {
   background: #f5f5f5;
+  min-height: 100px;
 }
 
-.room-list > h1 {
+.rooms > h1 {
   font-weight: bold;
   color: #999;
   padding: .5rem 1rem;
   border-bottom: 1px solid #ddd;
 }
 
+.rooms > p {
+  border-top: 1px solid #ddd;
+  padding: 1rem 0;
+  margin: 0;
+}
+
+.rooms > p > .btn {
+  display: block;
+  font-size: 1rem;
+  margin: 0 auto;
+  padding: .5rem 1rem;
+  border-radius: 3px;
+}
+
+.room-list {
+  max-height: 335px; /* XXX better computation needed */
+  overflow: scroll;
+}
+
 .room-list > .room-entry {
   padding: 1rem 1rem 0 .5rem;
 }
 
 .room-list > .room-entry > h2 {
   font-size: .85rem;
   color: #777;
 }
--- a/browser/components/loop/content/shared/js/actions.js
+++ b/browser/components/loop/content/shared/js/actions.js
@@ -123,28 +123,47 @@ loop.shared.actions = (function() {
     SetMute: Action.define("setMute", {
       // The part of the stream to enable, e.g. "audio" or "video"
       type: String,
       // Whether or not to enable the stream.
       enabled: Boolean
     }),
 
     /**
+     * Creates a new room.
+     * XXX: should move to some roomActions module - refs bug 1079284
+     */
+    CreateRoom: Action.define("createRoom", {
+      // The localized template to use to name the new room
+      // (eg. "Conversation {{conversationLabel}}").
+      nameTemplate: String,
+      roomOwner: String
+    }),
+
+    /**
+     * Rooms creation error.
+     * XXX: should move to some roomActions module - refs bug 1079284
+     */
+    CreateRoomError: Action.define("createRoomError", {
+      error: Error
+    }),
+
+    /**
      * Retrieves room list.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     GetAllRooms: Action.define("getAllRooms", {
     }),
 
     /**
      * An error occured while trying to fetch the room list.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     GetAllRoomsError: Action.define("getAllRoomsError", {
-      error: String
+      error: Error
     }),
 
     /**
      * Updates room list.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     UpdateRoomList: Action.define("updateRoomList", {
       roomList: Array
@@ -153,11 +172,11 @@ loop.shared.actions = (function() {
     /**
      * Primes localRoomStore with roomLocalId, which triggers the EmptyRoomView
      * to do any necessary setup.
      *
      * XXX should move to localRoomActions module
      */
     SetupEmptyRoom: Action.define("setupEmptyRoom", {
       localRoomId: String
-    }),
+    })
   };
 })();
--- a/browser/components/loop/content/shared/js/roomListStore.js
+++ b/browser/components/loop/content/shared/js/roomListStore.js
@@ -52,107 +52,283 @@ loop.store = loop.store || {};
    *                                registering to consume actions.
    * - {mozLoop}         mozLoop    The MozLoop API object.
    *
    * @extends {Backbone.Events}
    * @param {Object} options Options object.
    */
   function RoomListStore(options) {
     options = options || {};
-    this.storeState = {error: null, rooms: []};
 
     if (!options.dispatcher) {
       throw new Error("Missing option dispatcher");
     }
-    this.dispatcher = options.dispatcher;
+    this._dispatcher = options.dispatcher;
 
     if (!options.mozLoop) {
       throw new Error("Missing option mozLoop");
     }
-    this.mozLoop = options.mozLoop;
+    this._mozLoop = options.mozLoop;
 
-    this.dispatcher.register(this, [
+    this._dispatcher.register(this, [
+      "createRoom",
+      "createRoomError",
       "getAllRooms",
       "getAllRoomsError",
       "openRoom",
       "updateRoomList"
     ]);
   }
 
   RoomListStore.prototype = _.extend({
     /**
-     * Retrieves current store state.
+     * Maximum size given to createRoom; only 2 is supported (and is
+     * always passed) because that's what the user-experience is currently
+     * designed and tested to handle.
+     * @type {Number}
+     */
+    maxRoomCreationSize: 2,
+
+    /**
+     * The number of hours for which the room will exist.
+     * @type {Number}
+     */
+    defaultExpiresIn: 5,
+
+    /**
+     * Internal store state representation.
+     * @type {Object}
+     * @see  #getStoreState
+     */
+    _storeState: {
+      error: null,
+      pendingCreation: false,
+      pendingInitialRetrieval: false,
+      rooms: []
+    },
+
+    /**
+     * Retrieves current store state. The returned state object holds the
+     * following properties:
+     *
+     * - {Boolean} pendingCreation         Pending room creation flag.
+     * - {Boolean} pendingInitialRetrieval Pending initial list retrieval flag.
+     * - {Array}   rooms                   The current room list.
+     * - {Error}   error                   Latest error encountered, if any.
      *
      * @return {Object}
      */
     getStoreState: function() {
-      return this.storeState;
+      return this._storeState;
+    },
+
+    /**
+     * Updates store state and trigger a "change" event.
+     *
+     * @param {Object} newState The new store state.
+     */
+    setStoreState: function(newState) {
+      for (var key in newState) {
+        this._storeState[key] = newState[key];
+      }
+      this.trigger("change");
+    },
+
+    /**
+     * Registers mozLoop.rooms events.
+     */
+    startListeningToRoomEvents: function() {
+      // Rooms event registration
+      this._mozLoop.rooms.on("add", this._onRoomAdded.bind(this));
+      this._mozLoop.rooms.on("update", this._onRoomUpdated.bind(this));
+      this._mozLoop.rooms.on("remove", this._onRoomRemoved.bind(this));
+    },
+
+    /**
+     * Local proxy helper to dispatch an action.
+     *
+     * @param {Action} action The action to dispatch.
+     */
+    _dispatchAction: function(action) {
+      this._dispatcher.dispatch(action);
     },
 
     /**
-     * Updates store states and trigger a "change" event.
+     * Updates current room list when a new room is available.
      *
-     * @param {Object} state The new store state.
+     * @param {String} eventName     The event name (unused).
+     * @param {Object} addedRoomData The added room data.
+     */
+    _onRoomAdded: function(eventName, addedRoomData) {
+      addedRoomData.participants = [];
+      addedRoomData.ctime = new Date().getTime();
+      this._dispatchAction(new sharedActions.UpdateRoomList({
+        roomList: this._storeState.rooms.concat(new Room(addedRoomData))
+      }));
+    },
+
+    /**
+     * Executed when a room is updated.
+     *
+     * @param {String} eventName       The event name (unused).
+     * @param {Object} updatedRoomData The updated room data.
      */
-    setStoreState: function(state) {
-      this.storeState = state;
-      this.trigger("change");
+    _onRoomUpdated: function(eventName, updatedRoomData) {
+      this._dispatchAction(new sharedActions.UpdateRoomList({
+        roomList: this._storeState.rooms.map(function(room) {
+          return room.roomToken === updatedRoomData.roomToken ?
+                 updatedRoomData : room;
+        })
+      }));
     },
 
     /**
+     * Executed when a room is removed.
+     *
+     * @param {String} eventName       The event name (unused).
+     * @param {Object} removedRoomData The removed room data.
+     */
+    _onRoomRemoved: function(eventName, removedRoomData) {
+      this._dispatchAction(new sharedActions.UpdateRoomList({
+        roomList: this._storeState.rooms.filter(function(room) {
+          return room.roomToken !== removedRoomData.roomToken;
+        })
+      }));
+    },
+
+
+    /**
      * Maps and sorts the raw room list received from the mozLoop API.
      *
      * @param  {Array} rawRoomList Raw room list.
      * @return {Array}
      */
-    _processRawRoomList: function(rawRoomList) {
+    _processRoomList: function(rawRoomList) {
       if (!rawRoomList) {
         return [];
       }
       return rawRoomList
         .map(function(rawRoom) {
           return new Room(rawRoom);
         })
         .slice()
         .sort(function(a, b) {
           return b.ctime - a.ctime;
         });
     },
 
     /**
+     * Finds the next available room number in the provided room list.
+     *
+     * @param  {String} nameTemplate The room name template; should contain a
+     *                               {{conversationLabel}} placeholder.
+     * @return {Number}
+     */
+    findNextAvailableRoomNumber: function(nameTemplate) {
+      var searchTemplate = nameTemplate.replace("{{conversationLabel}}", "");
+      var searchRegExp = new RegExp("^" + searchTemplate + "(\\d+)$");
+
+      var roomNumbers = this._storeState.rooms.map(function(room) {
+        var match = searchRegExp.exec(room.roomName);
+        return match && match[1] ? parseInt(match[1], 10) : 0;
+      });
+
+      if (!roomNumbers.length) {
+        return 1;
+      }
+
+      return Math.max.apply(null, roomNumbers) + 1;
+    },
+
+    /**
+     * Generates a room names against the passed template string.
+     *
+     * @param  {String} nameTemplate The room name template.
+     * @return {String}
+     */
+    _generateNewRoomName: function(nameTemplate) {
+      var roomLabel = this.findNextAvailableRoomNumber(nameTemplate);
+      return nameTemplate.replace("{{conversationLabel}}", roomLabel);
+    },
+
+    /**
+     * Creates a new room.
+     *
+     * @param {sharedActions.CreateRoom} actionData The new room information.
+     */
+    createRoom: function(actionData) {
+      this.setStoreState({pendingCreation: true});
+
+      var roomCreationData = {
+        roomName:  this._generateNewRoomName(actionData.nameTemplate),
+        roomOwner: actionData.roomOwner,
+        maxSize:   this.maxRoomCreationSize,
+        expiresIn: this.defaultExpiresIn
+      };
+
+      this._mozLoop.rooms.create(roomCreationData, function(err) {
+        this.setStoreState({pendingCreation: false});
+        if (err) {
+         this._dispatchAction(new sharedActions.CreateRoomError({error: err}));
+        }
+      }.bind(this));
+    },
+
+    /**
+     * Executed when a room creation error occurs.
+     *
+     * @param {sharedActions.CreateRoomError} actionData The action data.
+     */
+    createRoomError: function(actionData) {
+      this.setStoreState({
+        error: actionData.error,
+        pendingCreation: false
+      });
+    },
+
+    /**
      * Gather the list of all available rooms from the MozLoop API.
      */
     getAllRooms: function() {
-      this.mozLoop.rooms.getAll(function(err, rawRoomList) {
+      this.setStoreState({pendingInitialRetrieval: true});
+      this._mozLoop.rooms.getAll(null, function(err, rawRoomList) {
         var action;
+
+        this.setStoreState({pendingInitialRetrieval: false});
+
         if (err) {
           action = new sharedActions.GetAllRoomsError({error: err});
         } else {
           action = new sharedActions.UpdateRoomList({roomList: rawRoomList});
         }
-        this.dispatcher.dispatch(action);
+
+        this._dispatchAction(action);
+
+        // We can only start listening to room events after getAll() has been
+        // called executed first.
+        this.startListeningToRoomEvents();
       }.bind(this));
     },
 
     /**
      * Updates current error state in case getAllRooms failed.
      *
-     * @param {sharedActions.UpdateRoomListError} actionData The action data.
+     * @param {sharedActions.GetAllRoomsError} actionData The action data.
      */
     getAllRoomsError: function(actionData) {
       this.setStoreState({error: actionData.error});
     },
 
     /**
      * Updates current room list.
      *
      * @param {sharedActions.UpdateRoomList} actionData The action data.
      */
     updateRoomList: function(actionData) {
       this.setStoreState({
         error: undefined,
-        rooms: this._processRawRoomList(actionData.roomList)
+        rooms: this._processRoomList(actionData.roomList)
       });
     },
   }, Backbone.Events);
 
   loop.store.RoomListStore = RoomListStore;
 })();
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -46,19 +46,20 @@ describe("loop.panel", function() {
       telemetryAdd: sinon.spy(),
       contacts: {
         getAll: function(callback) {
           callback(null, []);
         },
         on: sandbox.stub()
       },
       rooms: {
-        getAll: function(callback) {
+        getAll: function(version, callback) {
           callback(null, []);
-        }
+        },
+        on: sandbox.stub()
       }
     };
 
     document.mozL10n.initialize(navigator.mozLoop);
     // XXX prevent a race whenever mozL10n hasn't been initialized yet
     setTimeout(done, 0);
   });
 
@@ -620,17 +621,17 @@ describe("loop.panel", function() {
                                   true);
         });
 
       it("should notify the user when the operation failed", function() {
         fakeClient.requestCallUrl = function(_, cb) {
           cb("fake error");
         };
         sandbox.stub(notifications, "errorL10n");
-        var view = TestUtils.renderIntoDocument(loop.panel.CallUrlResult({
+        TestUtils.renderIntoDocument(loop.panel.CallUrlResult({
           notifications: notifications,
           client: fakeClient
         }));
 
         sinon.assert.calledOnce(notifications.errorL10n);
         sinon.assert.calledWithExactly(notifications.errorL10n,
                                        "unable_retrieve_url");
       });
@@ -699,41 +700,86 @@ describe("loop.panel", function() {
 
         TestUtils.SimulateNative.mouseOut(roomNode);
 
         expect(buttonNode.classList.contains("checked")).eql(false);
       });
   });
 
   describe("loop.panel.RoomList", function() {
-    var roomListStore, dispatcher;
+    var roomListStore, dispatcher, fakeEmail;
 
     beforeEach(function() {
+      fakeEmail = "fakeEmail@example.com";
       dispatcher = new loop.Dispatcher();
       roomListStore = new loop.store.RoomListStore({
         dispatcher: dispatcher,
         mozLoop: navigator.mozLoop
       });
+      roomListStore.setStoreState({
+        pendingCreation: false,
+        pendingInitialRetrieval: false,
+        rooms: [],
+        error: undefined
+      });
     });
 
     function createTestComponent() {
       return TestUtils.renderIntoDocument(loop.panel.RoomList({
         store: roomListStore,
-        dispatcher: dispatcher
+        dispatcher: dispatcher,
+        userDisplayName: fakeEmail
       }));
     }
 
     it("should dispatch a GetAllRooms action on mount", function() {
       var dispatch = sandbox.stub(dispatcher, "dispatch");
 
       createTestComponent();
 
       sinon.assert.calledOnce(dispatch);
       sinon.assert.calledWithExactly(dispatch, new sharedActions.GetAllRooms());
     });
+
+    it("should dispatch a CreateRoom action when clicking on the Start a " +
+       "conversation button",
+      function() {
+        navigator.mozLoop.userProfile = {email: fakeEmail};
+        var dispatch = sandbox.stub(dispatcher, "dispatch");
+        var view = createTestComponent();
+
+        TestUtils.Simulate.click(view.getDOMNode().querySelector("button"));
+
+        sinon.assert.calledWith(dispatch, new sharedActions.CreateRoom({
+          nameTemplate: "fakeText",
+          roomOwner: fakeEmail
+        }));
+      });
+
+    it("should disable the create button when a creation operation is ongoing",
+      function() {
+        var dispatch = sandbox.stub(dispatcher, "dispatch");
+        roomListStore.setStoreState({pendingCreation: true});
+
+        var view = createTestComponent();
+
+        var buttonNode = view.getDOMNode().querySelector("button[disabled]");
+        expect(buttonNode).to.not.equal(null);
+    });
+
+    it("should disable the create button when a list retrieval operation is pending",
+      function() {
+        var dispatch = sandbox.stub(dispatcher, "dispatch");
+        roomListStore.setStoreState({pendingInitialRetrieval: true});
+
+        var view = createTestComponent();
+
+        var buttonNode = view.getDOMNode().querySelector("button[disabled]");
+        expect(buttonNode).to.not.equal(null);
+    });
   });
 
   describe('loop.panel.ToSView', function() {
 
     it("should render when the value of loop.seenToS is not set", function() {
       var view = TestUtils.renderIntoDocument(loop.panel.ToSView());
 
       TestUtils.findRenderedDOMComponentWithClass(view, "terms-service");
--- a/browser/components/loop/test/shared/roomListStore_test.js
+++ b/browser/components/loop/test/shared/roomListStore_test.js
@@ -1,30 +1,55 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 var expect = chai.expect;
 
 describe("loop.store.Room", function () {
   "use strict";
+
   describe("#constructor", function() {
     it("should validate room values", function() {
       expect(function() {
         new loop.store.Room();
       }).to.Throw(Error, /missing required/);
     });
   });
 });
 
 describe("loop.store.RoomListStore", function () {
   "use strict";
 
   var sharedActions = loop.shared.actions;
   var sandbox, dispatcher;
 
+  var fakeRoomList = [{
+    roomToken: "_nxD4V4FflQ",
+    roomUrl: "http://sample/_nxD4V4FflQ",
+    roomName: "First Room Name",
+    maxSize: 2,
+    participants: [],
+    ctime: 1405517546
+  }, {
+    roomToken: "QzBbvGmIZWU",
+    roomUrl: "http://sample/QzBbvGmIZWU",
+    roomName: "Second Room Name",
+    maxSize: 2,
+    participants: [],
+    ctime: 1405517418
+  }, {
+    roomToken: "3jKS_Els9IU",
+    roomUrl: "http://sample/3jKS_Els9IU",
+    roomName: "Third Room Name",
+    maxSize: 3,
+    clientMaxSize: 2,
+    participants: [],
+    ctime: 1405518241
+  }];
+
   beforeEach(function() {
     sandbox = sinon.sandbox.create();
     dispatcher = new loop.Dispatcher();
   });
 
   afterEach(function() {
     sandbox.restore();
   });
@@ -38,93 +63,267 @@ describe("loop.store.RoomListStore", fun
 
     it("should throw an error if mozLoop is missing", function() {
       expect(function() {
         new loop.store.RoomListStore({dispatcher: dispatcher});
       }).to.Throw(/mozLoop/);
     });
   });
 
-  describe("#getAllRooms", function() {
-    var store, fakeMozLoop;
-    var fakeRoomList = [{
-      roomToken: "_nxD4V4FflQ",
-      roomUrl: "http://sample/_nxD4V4FflQ",
-      roomName: "First Room Name",
-      maxSize: 2,
-      participants: [],
-      ctime: 1405517546
-    }, {
-      roomToken: "QzBbvGmIZWU",
-      roomUrl: "http://sample/QzBbvGmIZWU",
-      roomName: "Second Room Name",
-      maxSize: 2,
-      participants: [],
-      ctime: 1405517418
-    }, {
-      roomToken: "3jKS_Els9IU",
-      roomUrl: "http://sample/3jKS_Els9IU",
-      roomName: "Third Room Name",
-      maxSize: 3,
-      clientMaxSize: 2,
-      participants: [],
-      ctime: 1405518241
-    }];
+  describe("constructed", function() {
+    var fakeMozLoop, store;
 
     beforeEach(function() {
       fakeMozLoop = {
         rooms: {
-          getAll: function(cb) {
-            cb(null, fakeRoomList);
-          }
+          create: function() {},
+          getAll: function() {},
+          on: sandbox.stub()
         }
       };
       store = new loop.store.RoomListStore({
         dispatcher: dispatcher,
         mozLoop: fakeMozLoop
       });
+      store.setStoreState({
+        error: undefined,
+        pendingCreation: false,
+        pendingInitialRetrieval: false,
+        rooms: []
+      });
     });
 
-    it("should trigger a list:changed event", function(done) {
-      store.on("change", function() {
-        done();
+    describe("MozLoop rooms event listeners", function() {
+      beforeEach(function() {
+        _.extend(fakeMozLoop.rooms, Backbone.Events);
+
+        fakeMozLoop.rooms.getAll = function(version, cb) {
+          cb(null, fakeRoomList);
+        };
+
+        store.getAllRooms(); // registers event listeners
+      });
+
+      describe("add", function() {
+        it("should add the room entry to the list", function() {
+          fakeMozLoop.rooms.trigger("add", "add", {
+            roomToken: "newToken",
+            roomUrl: "http://sample/newToken",
+            roomName: "New room",
+            maxSize: 2,
+            participants: [],
+            ctime: 1405517546
+          });
+
+          expect(store.getStoreState().rooms).to.have.length.of(4);
+        });
       });
 
-      dispatcher.dispatch(new sharedActions.GetAllRooms());
+      describe("update", function() {
+        it("should update a room entry", function() {
+          fakeMozLoop.rooms.trigger("update", "update", {
+            roomToken: "_nxD4V4FflQ",
+            roomUrl: "http://sample/_nxD4V4FflQ",
+            roomName: "Changed First Room Name",
+            maxSize: 2,
+            participants: [],
+            ctime: 1405517546
+          });
+
+          expect(store.getStoreState().rooms).to.have.length.of(3);
+          expect(store.getStoreState().rooms.some(function(room) {
+            return room.roomName === "Changed First Room Name";
+          })).eql(true);
+        });
+      });
+
+      describe("remove", function() {
+        it("should remove a room from the list", function() {
+          fakeMozLoop.rooms.trigger("remove", "remove", {
+            roomToken: "_nxD4V4FflQ"
+          });
+
+          expect(store.getStoreState().rooms).to.have.length.of(2);
+          expect(store.getStoreState().rooms.some(function(room) {
+            return room.roomToken === "_nxD4V4FflQ";
+          })).eql(false);
+        });
+      });
+    });
+
+    describe("#findNextAvailableRoomNumber", function() {
+      var fakeNameTemplate = "RoomWord {{conversationLabel}}";
+
+      it("should find next available room number from an empty room list",
+        function() {
+          store.setStoreState({rooms: []});
+
+          expect(store.findNextAvailableRoomNumber(fakeNameTemplate)).eql(1);
+        });
+
+      it("should find next available room number from a non empty room list",
+        function() {
+          store.setStoreState({
+            rooms: [{roomName: "RoomWord 1"}]
+          });
+
+          expect(store.findNextAvailableRoomNumber(fakeNameTemplate)).eql(2);
+        });
+
+      it("should not be sensitive to initial list order", function() {
+        store.setStoreState({
+          rooms: [{roomName: "RoomWord 99"}, {roomName: "RoomWord 98"}]
+        });
+
+        expect(store.findNextAvailableRoomNumber(fakeNameTemplate)).eql(100);
+      });
     });
 
-    it("should fetch the room list from the mozLoop API", function(done) {
-      store.once("change", function() {
+    describe("#createRoom", function() {
+      var fakeNameTemplate = "Conversation {{conversationLabel}}";
+      var fakeLocalRoomId = "777";
+      var fakeOwner = "fake@invalid";
+      var fakeRoomCreationData = {
+        nameTemplate: fakeNameTemplate,
+        roomOwner: fakeOwner
+      };
+
+      var fakeCreatedRoom = {
+        roomName: "Conversation 1",
+        roomToken: "fake",
+        roomUrl: "http://invalid",
+        maxSize: 42,
+        participants: [],
+        ctime: 1234567890
+      };
+
+      beforeEach(function() {
+        store.setStoreState({pendingCreation: false, rooms: []});
+      });
+
+      it("should request creation of a new room", function() {
+        sandbox.stub(fakeMozLoop.rooms, "create");
+
+        store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
+
+        sinon.assert.calledWith(fakeMozLoop.rooms.create, {
+          roomName: "Conversation 1",
+          roomOwner: fakeOwner,
+          maxSize: store.maxRoomCreationSize,
+          expiresIn: store.defaultExpiresIn
+        });
+      });
+
+      it("should store any creation encountered error", function() {
+        var err = new Error("fake");
+        sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
+          cb(err);
+        });
+
+        store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
+
+        expect(store.getStoreState().error).eql(err);
+      });
+
+      it("should switch the pendingCreation state flag to true", function() {
+        sandbox.stub(fakeMozLoop.rooms, "create");
+
+        store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
+
+        expect(store.getStoreState().pendingCreation).eql(true);
+      });
+
+      it("should switch the pendingCreation state flag to false once the " +
+         "operation is done", function() {
+        sandbox.stub(fakeMozLoop.rooms, "create", function(data, cb) {
+          cb();
+        });
+
+        store.createRoom(new sharedActions.CreateRoom(fakeRoomCreationData));
+
+        expect(store.getStoreState().pendingCreation).eql(false);
+      });
+    });
+
+    describe("#setStoreState", function() {
+      it("should update store state data", function() {
+        store.setStoreState({pendingCreation: true});
+
+        expect(store.getStoreState().pendingCreation).eql(true);
+      });
+
+      it("should trigger a `change` event", function(done) {
+        store.once("change", function() {
+          done();
+        });
+
+        store.setStoreState({pendingCreation: true});
+      });
+    });
+
+    describe("#getAllRooms", function() {
+      it("should fetch the room list from the MozLoop API", function() {
+        fakeMozLoop.rooms.getAll = function(version, cb) {
+          cb(null, fakeRoomList);
+        };
+
+        store.getAllRooms(new sharedActions.GetAllRooms());
+
         expect(store.getStoreState().error).to.be.a.undefined;
         expect(store.getStoreState().rooms).to.have.length.of(3);
-        done();
       });
 
-      dispatcher.dispatch(new sharedActions.GetAllRooms());
-    });
+      it("should order the room list using ctime desc", function() {
+        fakeMozLoop.rooms.getAll = function(version, cb) {
+          cb(null, fakeRoomList);
+        };
 
-    it("should order the room list using ctime desc", function(done) {
-      store.once("change", function() {
+        store.getAllRooms(new sharedActions.GetAllRooms());
+
         var storeState = store.getStoreState();
         expect(storeState.error).to.be.a.undefined;
         expect(storeState.rooms[0].ctime).eql(1405518241);
         expect(storeState.rooms[1].ctime).eql(1405517546);
         expect(storeState.rooms[2].ctime).eql(1405517418);
-        done();
+      });
+
+      it("should report an error", function() {
+        var err = new Error("fake");
+        fakeMozLoop.rooms.getAll = function(version, cb) {
+          cb(err);
+        };
+
+        dispatcher.dispatch(new sharedActions.GetAllRooms());
+
+        expect(store.getStoreState().error).eql(err);
       });
 
-      dispatcher.dispatch(new sharedActions.GetAllRooms());
-    });
+      it("should register event listeners after the list is retrieved",
+        function() {
+          sandbox.stub(store, "startListeningToRoomEvents");
+          fakeMozLoop.rooms.getAll = function(version, cb) {
+            cb(null, fakeRoomList);
+          };
 
-    it("should report an error", function() {
-      fakeMozLoop.rooms.getAll = function(cb) {
-        cb("fakeError");
-      };
+          store.getAllRooms();
+
+          sinon.assert.calledOnce(store.startListeningToRoomEvents);
+        });
 
-      store.once("change", function() {
-        var storeState = store.getStoreState();
-        expect(storeState.error).eql("fakeError");
+      it("should set the pendingInitialRetrieval flag to true", function() {
+        store.getAllRooms();
+
+        expect(store.getStoreState().pendingInitialRetrieval).eql(true);
       });
 
-      dispatcher.dispatch(new sharedActions.GetAllRooms());
+      it("should set pendingInitialRetrieval to false once the action is " +
+         "performed", function() {
+        fakeMozLoop.rooms.getAll = function(version, cb) {
+          cb(null, fakeRoomList);
+        };
+
+        store.getAllRooms();
+
+        expect(store.getStoreState().pendingInitialRetrieval).eql(false);
+      });
     });
   });
 });
--- a/browser/components/loop/ui/fake-mozLoop.js
+++ b/browser/components/loop/ui/fake-mozLoop.js
@@ -60,14 +60,15 @@ navigator.mozLoop = {
   copyString: function() {},
   contacts: {
     getAll: function(callback) {
       callback(null, []);
     },
     on: function() {}
   },
   rooms: {
-    getAll: function(callback) {
+    getAll: function(version, callback) {
       callback(null, fakeRooms);
-    }
+    },
+    on: function() {}
   },
   fxAEnabled: true
 };
--- a/browser/components/loop/ui/ui-showcase.css
+++ b/browser/components/loop/ui/ui-showcase.css
@@ -11,38 +11,38 @@
 .showcase {
   min-width: 350px;
   max-width: 730px;
 }
 
 .showcase > header {
   position: fixed;
   top: 0;
-  background-color: #fbfbfb;
+  background-color: #fff;
   z-index: 100000;
   width: 100%;
   padding-bottom: 1em;
 }
 
 .showcase > header > h1,
 .showcase > section > h1 {
   font-size: 2em;
   font-weight: bold;
   margin: .5em 0;
 }
 
 .showcase-menu > a {
   margin-right: .5em;
-  padding: .4rem;
+  padding: .2rem;
   margin-top: .2rem;
 }
 
 .showcase > section {
   position: relative;
-  padding-top: 14em;
+  padding-top: 15em;
   clear: both;
 }
 
 .showcase > section > h1 {
   margin: 1em 0;
   border-bottom: 1px solid #aaa;
 }
 
@@ -64,18 +64,18 @@
   margin: 1.5em 0;
 }
 
 .showcase > section .example > h3 {
   font-size: 1.2em;
   font-weight: bold;
   border-bottom: 1px dashed #aaa;
   margin: 1em 0;
-  margin-top: -14em;
-  padding-top: 14em;
+  margin-top: -15em;
+  padding-top: 15em;
   text-align: left;
 }
 
 .showcase > section .example > h3 a {
   text-decoration: none;
   color: #555;
 }
 
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2339,22 +2339,17 @@ let E10SUINotification = {
   // e10s testing period to Nightly users.
   CURRENT_NOTICE_COUNT: 1,
   CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
   PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
 
   checkStatus: function() {
     let skipE10sChecks = false;
     try {
-      // This order matters, because
-      // browser.tabs.remote.autostart.disabled-because-using-a11y is not
-      // always defined and will throw when not present.
-      // privacy.trackingprotection.enabled is always defined.
       skipE10sChecks = (UpdateChannel.get() != "nightly") ||
-                       Services.prefs.getBoolPref("privacy.trackingprotection.enabled") ||
                        Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
     } catch(e) {}
 
     if (skipE10sChecks) {
       return;
     }
 
     if (Services.appinfo.browserTabsRemoteAutostart) {
--- a/browser/components/tabview/test/browser.ini
+++ b/browser/components/tabview/test/browser.ini
@@ -1,9 +1,11 @@
 [DEFAULT]
+skip-if = e10s # Bug 1092281
+
 support-files =
   dummy_page.html
   head.js
   search1.html
   search2.html
   test_bug600645.html
   test_bug644097.html
   test_bug678374.html
--- a/browser/components/translation/test/browser_translation_exceptions.js
+++ b/browser/components/translation/test/browser_translation_exceptions.js
@@ -1,17 +1,18 @@
 /* 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/. */
 
 // tests the translation infobar, using a fake 'Translation' implementation.
 
 let tmp = {};
 Cu.import("resource:///modules/translation/Translation.jsm", tmp);
-let {Translation} = tmp;
+Cu.import("resource://gre/modules/Promise.jsm", tmp);
+let {Translation, Promise} = tmp;
 
 const kLanguagesPref = "browser.translation.neverForLanguages";
 const kShowUIPref = "browser.translation.ui.show";
 
 function test() {
   waitForExplicitFinish();
 
   Services.prefs.setBoolPref(kShowUIPref, true);
--- a/browser/config/tooltool-manifests/win32/releng.manifest
+++ b/browser/config/tooltool-manifests/win32/releng.manifest
@@ -1,18 +1,18 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
-"size": 51,
-"digest": "c8e40edb314eeabfb92c77cf5ff9a7857033f15dd65a00349bcf9e3e5b75624afc71f733b2ff7e029c20a78313038409c2bd022bf7e5a7e0c487fc2c2d640986",
+"size": 176,
+"digest": "2809058907ac5eefdc394113d2e4fe76ba559ac61c2eca2f88e7a12a74bdf44a15d9039fa8aa229f7362a14b67d67395063f68147ae098beac5dfcc78aff98da",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
 "size": 168320,
 "digest": "c0f4a2da0b07ca6fc69290fbc5ed68f56c6b1ba4d593b220fd49b14ac4885e6ec949e695fd9a7ac464e0e86b652e99f6bd4af849fec072264b29a8f9686d2fc4",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2"
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -83,17 +83,18 @@ browser.jar:
     content/browser/devtools/webaudioeditor/views/context.js           (webaudioeditor/views/context.js)
     content/browser/devtools/webaudioeditor/views/inspector.js         (webaudioeditor/views/inspector.js)
     content/browser/devtools/profiler.xul                              (profiler/profiler.xul)
     content/browser/devtools/profiler.js                               (profiler/profiler.js)
     content/browser/devtools/ui-recordings.js                          (profiler/ui-recordings.js)
     content/browser/devtools/ui-profile.js                             (profiler/ui-profile.js)
 #ifdef MOZ_DEVTOOLS_PERFTOOLS
     content/browser/devtools/performance.xul                           (performance/performance.xul)
-    content/browser/devtools/performance.js                            (performance/performance.js)
+    content/browser/devtools/performance/controller.js                 (performance/controller.js)
+    content/browser/devtools/performance/views/main.js                 (performance/views/main.js)
 #endif
     content/browser/devtools/responsivedesign/resize-commands.js       (responsivedesign/resize-commands.js)
     content/browser/devtools/commandline.css                           (commandline/commandline.css)
     content/browser/devtools/commandlineoutput.xhtml                   (commandline/commandlineoutput.xhtml)
     content/browser/devtools/commandlinetooltip.xhtml                  (commandline/commandlinetooltip.xhtml)
     content/browser/devtools/commandline/commands-index.js             (commandline/commands-index.js)
     content/browser/devtools/framework/toolbox-window.xul              (framework/toolbox-window.xul)
     content/browser/devtools/framework/toolbox-options.xul             (framework/toolbox-options.xul)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/controller.js
@@ -0,0 +1,137 @@
+/* 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/. */
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/devtools/Loader.jsm");
+Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
+
+devtools.lazyRequireGetter(this, "Services");
+devtools.lazyRequireGetter(this, "promise");
+devtools.lazyRequireGetter(this, "EventEmitter",
+  "devtools/toolkit/event-emitter");
+devtools.lazyRequireGetter(this, "DevToolsUtils",
+  "devtools/toolkit/DevToolsUtils");
+
+// Events emitted by the `PerformanceController`
+const EVENTS = {
+  // When a recording is started or stopped via the controller
+  RECORDING_STARTED: "Performance:RecordingStarted",
+  RECORDING_STOPPED: "Performance:RecordingStopped",
+
+  // Emitted by the PerformanceView on record button click
+  UI_START_RECORDING: "Performance:UI:StartRecording",
+  UI_STOP_RECORDING: "Performance:UI:StopRecording"
+};
+
+/**
+ * The current target and the profiler connection, set by this tool's host.
+ */
+let gToolbox, gTarget, gFront;
+
+/**
+ * Initializes the profiler controller and views.
+ */
+let startupPerformance = Task.async(function*() {
+  yield promise.all([
+    PrefObserver.register(),
+    PerformanceController.initialize(),
+    PerformanceView.initialize()
+  ]);
+});
+
+/**
+ * Destroys the profiler controller and views.
+ */
+let shutdownPerformance = Task.async(function*() {
+  yield promise.all([
+    PrefObserver.unregister(),
+    PerformanceController.destroy(),
+    PerformanceView.destroy()
+  ]);
+});
+
+/**
+ * Observes pref changes on the devtools.profiler branch and triggers the
+ * required frontend modifications.
+ */
+let PrefObserver = {
+  register: function() {
+    this.branch = Services.prefs.getBranch("devtools.profiler.");
+    this.branch.addObserver("", this, false);
+  },
+  unregister: function() {
+    this.branch.removeObserver("", this);
+  },
+  observe: function(subject, topic, pref) {
+    Prefs.refresh();
+  }
+};
+
+/**
+ * Functions handling target-related lifetime events and
+ * UI interaction.
+ */
+let PerformanceController = {
+  /**
+   * Listen for events emitted by the current tab target and
+   * main UI events.
+   */
+  initialize: function() {
+    this.startRecording = this.startRecording.bind(this);
+    this.stopRecording = this.stopRecording.bind(this);
+
+    PerformanceView.on(EVENTS.UI_START_RECORDING, this.startRecording);
+    PerformanceView.on(EVENTS.UI_STOP_RECORDING, this.stopRecording);
+  },
+
+  /**
+   * Remove events handled by the PerformanceController
+   */
+  destroy: function() {
+    PerformanceView.off(EVENTS.UI_START_RECORDING, this.startRecording);
+    PerformanceView.off(EVENTS.UI_STOP_RECORDING, this.stopRecording);
+  },
+
+  /**
+   * Starts recording with the PerformanceFront. Emits `EVENTS.RECORDING_STARTED`
+   * when the front is starting to record.
+   */
+  startRecording: Task.async(function *() {
+    yield gFront.startRecording();
+    this.emit(EVENTS.RECORDING_STARTED);
+  }),
+
+  /**
+   * Stops recording with the PerformanceFront. Emits `EVENTS.RECORDING_STOPPED`
+   * when the front stops recording.
+   */
+  stopRecording: Task.async(function *() {
+    let results = yield gFront.stopRecording();
+    this.emit(EVENTS.RECORDING_STOPPED, results);
+  })
+};
+
+/**
+ * Convenient way of emitting events from the controller.
+ */
+EventEmitter.decorate(PerformanceController);
+
+/**
+ * Shortcuts for accessing various profiler preferences.
+ */
+const Prefs = new ViewHelpers.Prefs("devtools.profiler", {
+});
+
+/**
+ * DOM query helpers.
+ */
+function $(selector, target = document) {
+  return target.querySelector(selector);
+}
+function $$(selector, target = document) {
+  return target.querySelectorAll(selector);
+}
deleted file mode 100644
--- a/browser/devtools/performance/performance.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/devtools/Loader.jsm");
-Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-
-devtools.lazyRequireGetter(this, "Services");
-devtools.lazyRequireGetter(this, "promise");
-devtools.lazyRequireGetter(this, "EventEmitter",
-  "devtools/toolkit/event-emitter");
-devtools.lazyRequireGetter(this, "DevToolsUtils",
-  "devtools/toolkit/DevToolsUtils");
-
-/**
- * The current target and the profiler connection, set by this tool's host.
- */
-let gToolbox, gTarget, gFront;
-
-/**
- * Initializes the profiler controller and views.
- */
-let startupPerformance = Task.async(function*() {
-  yield promise.all([
-    PrefObserver.register(),
-    EventsHandler.initialize()
-  ]);
-});
-
-/**
- * Destroys the profiler controller and views.
- */
-let shutdownPerformance = Task.async(function*() {
-  yield promise.all([
-    PrefObserver.unregister(),
-    EventsHandler.destroy()
-  ]);
-});
-
-/**
- * Observes pref changes on the devtools.profiler branch and triggers the
- * required frontend modifications.
- */
-let PrefObserver = {
-  register: function() {
-    this.branch = Services.prefs.getBranch("devtools.profiler.");
-    this.branch.addObserver("", this, false);
-  },
-  unregister: function() {
-    this.branch.removeObserver("", this);
-  },
-  observe: function(subject, topic, pref) {
-    Prefs.refresh();
-  }
-};
-
-/**
- * Functions handling target-related lifetime events.
- */
-let EventsHandler = {
-  /**
-   * Listen for events emitted by the current tab target.
-   */
-  initialize: function() {
-  },
-
-  /**
-   * Remove events emitted by the current tab target.
-   */
-  destroy: function() {
-  }
-};
-
-/**
- * Shortcuts for accessing various profiler preferences.
- */
-const Prefs = new ViewHelpers.Prefs("devtools.profiler", {
-});
-
-/**
- * Convenient way of emitting events from the panel window.
- */
-EventEmitter.decorate(this);
-
-/**
- * DOM query helpers.
- */
-function $(selector, target = document) {
-  return target.querySelector(selector);
-}
-function $$(selector, target = document) {
-  return target.querySelectorAll(selector);
-}
--- a/browser/devtools/performance/performance.xul
+++ b/browser/devtools/performance/performance.xul
@@ -9,17 +9,18 @@
 <?xml-stylesheet href="chrome://browser/skin/devtools/performance.css" type="text/css"?>
 <!DOCTYPE window [
   <!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
   %profilerDTD;
 ]>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script src="chrome://browser/content/devtools/theme-switching.js"/>
-  <script type="application/javascript" src="performance.js"/>
+  <script type="application/javascript" src="performance/controller.js"/>
+  <script type="application/javascript" src="performance/views/main.js"/>
 
   <vbox class="theme-body" flex="1">
     <toolbar id="performance-toolbar" class="devtools-toolbar">
       <hbox id="performance-toolbar-controls-recordings" class="devtools-toolbarbutton-group">
         <toolbarbutton id="record-button"
                        class="devtools-toolbarbutton"
                        tooltiptext="&profilerUI.recordButton.tooltip;"/>
         <toolbarbutton id="clear-button"
--- a/browser/devtools/performance/test/browser.ini
+++ b/browser/devtools/performance/test/browser.ini
@@ -23,8 +23,9 @@ support-files =
 # needs shared connection with profiler's shared connection
 #[browser_perf-shared-connection-01.js]
 [browser_perf-shared-connection-02.js]
 [browser_perf-shared-connection-03.js]
 # bug 1077464
 #[browser_perf-shared-connection-04.js]
 [browser_perf-data-samples.js]
 [browser_perf-data-massaging-01.js]
+[browser_perf-ui-recording.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-ui-recording.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the controller handles recording via the `stopwatch` button
+ * in the UI.
+ */
+let WAIT_TIME = 10;
+
+function spawnTest () {
+  let { panel } = yield initPerformance(SIMPLE_URL);
+  let { EVENTS, PerformanceController } = panel.panelWin;
+  let front = panel.panelWin.gFront;
+
+  ok(!nsIProfilerModule.IsActive(),
+    "The built-in profiler module should not have been automatically started.");
+
+  yield startRecording(panel);
+  busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
+
+  ok(nsIProfilerModule.IsActive(),
+    "The built-in profiler module should now be active.");
+
+  yield stopRecording(panel);
+
+  ok(nsIProfilerModule.IsActive(),
+    "The built-in profiler module should still be active.");
+
+  yield teardown(panel);
+  finish();
+}
--- a/browser/devtools/performance/test/head.js
+++ b/browser/devtools/performance/test/head.js
@@ -202,8 +202,64 @@ function busyWait(time) {
   let stack;
   while (Date.now() - start < time) { stack = Components.stack; }
 }
 
 function idleWait(time) {
   return DevToolsUtils.waitForTime(time);
 }
 
+function* startRecording(panel) {
+  let win = panel.panelWin;
+  let clicked = panel.panelWin.PerformanceView.once(win.EVENTS.UI_START_RECORDING);
+  let started = panel.panelWin.PerformanceController.once(win.EVENTS.RECORDING_STARTED);
+  let button = win.$("#record-button");
+
+  ok(!button.hasAttribute("checked"),
+    "The record button should not be checked yet.");
+
+  ok(!button.hasAttribute("locked"),
+    "The record button should not be locked yet.");
+
+  EventUtils.synthesizeMouseAtCenter(button, {}, win);
+
+  yield clicked;
+
+  ok(button.hasAttribute("checked"),
+    "The record button should now be checked.");
+  ok(button.hasAttribute("locked"),
+    "The record button should be locked.");
+
+  yield started;
+
+  ok(button.hasAttribute("checked"),
+    "The record button should still be checked.");
+  ok(!button.hasAttribute("locked"),
+    "The record button should not be locked.");
+}
+
+function* stopRecording(panel) {
+  let win = panel.panelWin;
+  let clicked = panel.panelWin.PerformanceView.once(win.EVENTS.UI_STOP_RECORDING);
+  let ended = panel.panelWin.PerformanceController.once(win.EVENTS.RECORDING_STOPPED);
+  let button = win.$("#record-button");
+
+  ok(button.hasAttribute("checked"),
+    "The record button should already be checked.");
+  ok(!button.hasAttribute("locked"),
+    "The record button should not be locked yet.");
+
+  EventUtils.synthesizeMouseAtCenter(button, {}, win);
+
+  yield clicked;
+
+  ok(!button.hasAttribute("checked"),
+    "The record button should not be checked.");
+  ok(button.hasAttribute("locked"),
+    "The record button should be locked.");
+
+  yield ended;
+
+  ok(!button.hasAttribute("checked"),
+    "The record button should not be checked.");
+  ok(!button.hasAttribute("locked"),
+    "The record button should not be locked.");
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/views/main.js
@@ -0,0 +1,61 @@
+/* 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/. */
+"use strict";
+
+/**
+ * Master view handler for the performance tool.
+ */
+let PerformanceView = {
+  /**
+   * Sets up the view with event binding.
+   */
+  initialize: function () {
+    this._recordButton = $("#record-button");
+
+    this._onRecordButtonClick = this._onRecordButtonClick.bind(this);
+    this._unlockRecordButton = this._unlockRecordButton.bind(this);
+
+    this._recordButton.addEventListener("mouseup", this._onRecordButtonClick);
+
+    // Bind to controller events to unlock the record button
+    PerformanceController.on(EVENTS.RECORDING_STARTED, this._unlockRecordButton);
+    PerformanceController.on(EVENTS.RECORDING_STOPPED, this._unlockRecordButton);
+  },
+
+  /**
+   * Unbinds events.
+   */
+  destroy: function () {
+    this._recordButton.removeEventListener("mouseup", this._onRecordButtonClick);
+    PerformanceController.off(EVENTS.RECORDING_STARTED, this._unlockRecordButton);
+    PerformanceController.off(EVENTS.RECORDING_STOPPED, this._unlockRecordButton);
+  },
+
+  /**
+   * Removes the `locked` attribute on the record button.
+   */
+  _unlockRecordButton: function () {
+    this._recordButton.removeAttribute("locked");
+  },
+
+  /**
+   * Handler for clicking the record button.
+   */
+  _onRecordButtonClick: function (e) {
+    if (this._recordButton.hasAttribute("checked")) {
+      this._recordButton.removeAttribute("checked");
+      this._recordButton.setAttribute("locked", "true");
+      this.emit(EVENTS.UI_STOP_RECORDING);
+    } else {
+      this._recordButton.setAttribute("checked", "true");
+      this._recordButton.setAttribute("locked", "true");
+      this.emit(EVENTS.UI_START_RECORDING);
+    }
+  }
+};
+
+/**
+ * Convenient way of emitting events from the view.
+ */
+EventEmitter.decorate(PerformanceView);
--- a/browser/devtools/shared/test/head.js
+++ b/browser/devtools/shared/test/head.js
@@ -30,19 +30,18 @@ function addTab(aURL, aCallback)
     browser.removeEventListener("load", onTabLoad, true);
     aCallback(browser, tab, browser.contentDocument);
   }
 
   browser.addEventListener("load", onTabLoad, true);
 }
 
 function promiseTab(aURL) {
-  let deferred = Promise.defer();
-  addTab(aURL, deferred.resolve);
-  return deferred.promise;
+  return new Promise(resolve =>
+    addTab(aURL, resolve));
 }
 
 registerCleanupFunction(function tearDown() {
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 
   console = undefined;
@@ -133,16 +132,16 @@ function oneTimeObserve(name, callback) 
   };
   Services.obs.addObserver(func, name, false);
 }
 
 function* createHost(type = "bottom", src = "data:text/html;charset=utf-8,") {
   let host = new Hosts[type](gBrowser.selectedTab);
   let iframe = yield host.create();
 
-  let loaded = Promise.defer();
-  let domHelper = new DOMHelpers(iframe.contentWindow);
-  iframe.setAttribute("src", src);
-  domHelper.onceDOMReady(loaded.resolve);
-  yield loaded.promise;
+  yield new Promise(resolve => {
+    let domHelper = new DOMHelpers(iframe.contentWindow);
+    iframe.setAttribute("src", src);
+    domHelper.onceDOMReady(resolve);
+  });
 
   return [host, iframe.contentWindow, iframe.contentDocument];
 }
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,4 +1,4 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.0.907
+Current extension version is: 1.0.937
 
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -17,18 +17,18 @@
 /*jshint globalstrict: false */
 /* globals PDFJS */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '1.0.907';
-PDFJS.build = 'e9072ac';
+PDFJS.version = '1.0.937';
+PDFJS.build = '308646d';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* Copyright 2012 Mozilla Foundation
@@ -2794,16 +2794,18 @@ var Metadata = PDFJS.Metadata = (functio
 })();
 
 
 // <canvas> contexts store most of the state we need natively.
 // However, PDF needs a bit more state, which we store here.
 
 // Minimal font size that would be used during canvas fillText operations.
 var MIN_FONT_SIZE = 16;
+// Maximum font size that would be used during canvas fillText operations.
+var MAX_FONT_SIZE = 100;
 var MAX_GROUP_SIZE = 4096;
 
 var COMPILE_TYPE3_GLYPHS = true;
 
 function createScratchCanvas(width, height) {
   var canvas = document.createElement('canvas');
   canvas.width = width;
   canvas.height = height;
@@ -3994,19 +3996,19 @@ var CanvasGraphics = (function CanvasGra
 
       var italic = fontObj.italic ? 'italic' : 'normal';
       var typeface = '"' + name + '", ' + fontObj.fallbackName;
 
       // Some font backends cannot handle fonts below certain size.
       // Keeping the font at minimal size and using the fontSizeScale to change
       // the current transformation matrix before the fillText/strokeText.
       // See https://bugzilla.mozilla.org/show_bug.cgi?id=726227
-      var browserFontSize = size >= MIN_FONT_SIZE ? size : MIN_FONT_SIZE;
-      this.current.fontSizeScale = browserFontSize !== MIN_FONT_SIZE ? 1.0 :
-                                   size / MIN_FONT_SIZE;
+      var browserFontSize = size < MIN_FONT_SIZE ? MIN_FONT_SIZE :
+                            size > MAX_FONT_SIZE ? MAX_FONT_SIZE : size;
+      this.current.fontSizeScale = size / browserFontSize;
 
       var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
       this.ctx.font = rule;
     },
     setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
       this.current.textRenderingMode = mode;
     },
     setTextRise: function CanvasGraphics_setTextRise(rise) {
@@ -4231,19 +4233,21 @@ var CanvasGraphics = (function CanvasGra
       var font = current.font;
       var fontSize = current.fontSize;
       var fontDirection = current.fontDirection;
       var charSpacing = current.charSpacing;
       var wordSpacing = current.wordSpacing;
       var textHScale = current.textHScale * fontDirection;
       var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
       var glyphsLength = glyphs.length;
+      var isTextInvisible =
+        current.textRenderingMode === TextRenderingMode.INVISIBLE;
       var i, glyph, width;
 
-      if (fontSize === 0) {
+      if (isTextInvisible || fontSize === 0) {
         return;
       }
 
       ctx.save();
       ctx.transform.apply(ctx, current.textMatrix);
       ctx.translate(current.x, current.y);
 
       ctx.scale(textHScale, fontDirection);
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -17,18 +17,18 @@
 /*jshint globalstrict: false */
 /* globals PDFJS */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '1.0.907';
-PDFJS.build = 'e9072ac';
+PDFJS.version = '1.0.937';
+PDFJS.build = '308646d';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* Copyright 2012 Mozilla Foundation
@@ -4637,17 +4637,17 @@ var WidgetAnnotation = (function WidgetA
     var namedItem = dict;
     var ref = params.ref;
     while (namedItem) {
       var parent = namedItem.get('Parent');
       var parentRef = namedItem.getRaw('Parent');
       var name = namedItem.get('T');
       if (name) {
         fieldName.unshift(stringToPDFString(name));
-      } else {
+      } else if (parent && ref) {
         // The field name is absent, that means more than one field
         // with the same name may exist. Replacing the empty name
         // with the '`' plus index in the parent's 'Kids' array.
         // This is not in the PDF spec but necessary to id the
         // the input controls.
         var kids = parent.get('Kids');
         var j, jj;
         for (j = 0, jj = kids.length; j < jj; j++) {
@@ -34605,28 +34605,62 @@ var JpxImage = (function JpxImageClosure
           lbox = length - position + headerSize;
         }
         if (lbox < headerSize) {
           throw new Error('JPX Error: Invalid box field size');
         }
         var dataLength = lbox - headerSize;
         var jumpDataLength = true;
         switch (tbox) {
-          case 0x6A501A1A: // 'jP\032\032'
-            // TODO
-            break;
           case 0x6A703268: // 'jp2h'
             jumpDataLength = false; // parsing child boxes
             break;
           case 0x636F6C72: // 'colr'
-            // TODO
+            // Colorspaces are not used, the CS from the PDF is used.
+            var method = data[position];
+            var precedence = data[position + 1];
+            var approximation = data[position + 2];
+            if (method === 1) {
+              // enumerated colorspace
+              var colorspace = readUint32(data, position + 3);
+              switch (colorspace) {
+                case 16: // this indicates a sRGB colorspace
+                case 17: // this indicates a grayscale colorspace
+                case 18: // this indicates a YUV colorspace
+                  break;
+                default:
+                  warn('Unknown colorspace ' + colorspace);
+                  break;
+              }
+            } else if (method === 2) {
+              info('ICC profile not supported');
+            }
             break;
           case 0x6A703263: // 'jp2c'
             this.parseCodestream(data, position, position + dataLength);
             break;
+          case 0x6A502020: // 'jP\024\024'
+            if (0x0d0a870a !== readUint32(data, position)) {
+              warn('Invalid JP2 signature');
+            }
+            break;
+          // The following header types are valid but currently not used:
+          case 0x6A501A1A: // 'jP\032\032'
+          case 0x66747970: // 'ftyp'
+          case 0x72726571: // 'rreq'
+          case 0x72657320: // 'res '
+          case 0x69686472: // 'ihdr'
+            break;
+          default:
+            var headerType = String.fromCharCode((tbox >> 24) & 0xFF,
+                                                 (tbox >> 16) & 0xFF,
+                                                 (tbox >> 8) & 0xFF,
+                                                 tbox & 0xFF);
+            warn('Unsupported header type ' + tbox + ' (' + headerType + ')');
+            break;
         }
         if (jumpDataLength) {
           position += dataLength;
         }
       }
     },
     parseImageProperties: function JpxImage_parseImageProperties(stream) {
       var newByte = stream.getByte();
@@ -35048,16 +35082,21 @@ var JpxImage = (function JpxImageClosure
         precinctNumber = pj + pi * precinctParameters.numprecinctswide;
         codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);
         codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);
         codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);
         codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);
         codeblock.precinctNumber = precinctNumber;
         codeblock.subbandType = subband.type;
         codeblock.Lblock = 3;
+
+        if (codeblock.tbx1_ <= codeblock.tbx0_ ||
+            codeblock.tby1_ <= codeblock.tby0_) {
+          continue;
+        }
         codeblocks.push(codeblock);
         // building precinct for the sub-band
         var precinct = precincts[precinctNumber];
         if (precinct !== undefined) {
           if (i < precinct.cbxMin) {
             precinct.cbxMin = i;
           } else if (i > precinct.cbxMax) {
             precinct.cbxMax = i;
@@ -35330,38 +35369,38 @@ var JpxImage = (function JpxImageClosure
       }
       value = readBits(7);
       return value + 37;
     }
     var tileIndex = context.currentTile.index;
     var tile = context.tiles[tileIndex];
     var packetsIterator = tile.packetsIterator;
     while (position < dataLength) {
-      var packet = packetsIterator.nextPacket();
+      alignToByte();
       if (!readBits(1)) {
-        alignToByte();
         continue;
       }
+      var packet = packetsIterator.nextPacket();
       var layerNumber = packet.layerNumber;
       var queue = [], codeblock;
       for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
         codeblock = packet.codeblocks[i];
         var precinct = codeblock.precinct;
         var codeblockColumn = codeblock.cbx - precinct.cbxMin;
         var codeblockRow = codeblock.cby - precinct.cbyMin;
         var codeblockIncluded = false;
         var firstTimeInclusion = false;
         var valueReady;
-        if ('included' in codeblock) {
+        if (codeblock['included'] !== undefined) {
           codeblockIncluded = !!readBits(1);
         } else {
           // reading inclusion tree
           precinct = codeblock.precinct;
           var inclusionTree, zeroBitPlanesTree;
-          if ('inclusionTree' in precinct) {
+          if (precinct['inclusionTree'] !== undefined) {
             inclusionTree = precinct.inclusionTree;
           } else {
             // building inclusion and zero bit-planes trees
             var width = precinct.cbxMax - precinct.cbxMin + 1;
             var height = precinct.cbyMax - precinct.cbyMin + 1;
             inclusionTree = new InclusionTree(width, height, layerNumber);
             zeroBitPlanesTree = new TagTree(width, height);
             precinct.inclusionTree = inclusionTree;
@@ -35416,17 +35455,17 @@ var JpxImage = (function JpxImageClosure
           codingpasses: codingpasses,
           dataLength: codedDataLength
         });
       }
       alignToByte();
       while (queue.length > 0) {
         var packetItem = queue.shift();
         codeblock = packetItem.codeblock;
-        if (!('data' in codeblock)) {
+        if (codeblock['data'] === undefined) {
           codeblock.data = [];
         }
         codeblock.data.push({
           data: data,
           start: offset + position,
           end: offset + position + packetItem.dataLength,
           codingpasses: packetItem.codingpasses
         });
@@ -35446,17 +35485,17 @@ var JpxImage = (function JpxImageClosure
 
     for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
       var codeblock = codeblocks[i];
       var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
       var blockHeight = codeblock.tby1_ - codeblock.tby0_;
       if (blockWidth === 0 || blockHeight === 0) {
         continue;
       }
-      if (!('data' in codeblock)) {
+      if (codeblock['data'] === undefined) {
         continue;
       }
 
       var bitModel, currentCodingpassType;
       bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
                               codeblock.zeroBitPlanes, mb);
       currentCodingpassType = 2; // first bit plane starts from cleanup
 
@@ -35701,20 +35740,20 @@ var JpxImage = (function JpxImageClosure
     return resultImages;
   }
   function initializeTile(context, tileIndex) {
     var siz = context.SIZ;
     var componentsCount = siz.Csiz;
     var tile = context.tiles[tileIndex];
     for (var c = 0; c < componentsCount; c++) {
       var component = tile.components[c];
-      var qcdOrQcc = (c in context.currentTile.QCC ?
+      var qcdOrQcc = (context.currentTile.QCC[c] !== undefined ?
         context.currentTile.QCC[c] : context.currentTile.QCD);
       component.quantizationParameters = qcdOrQcc;
-      var codOrCoc = (c in context.currentTile.COC ?
+      var codOrCoc = (context.currentTile.COC[c] !== undefined  ?
         context.currentTile.COC[c] : context.currentTile.COD);
       component.codingStyleParameters = codOrCoc;
     }
     tile.codingStyleDefaultParameters = context.currentTile.COD;
   }
 
   // Section B.10.2 Tag trees
   var TagTree = (function TagTreeClosure() {
@@ -35733,17 +35772,17 @@ var JpxImage = (function JpxImageClosure
       }
     }
     TagTree.prototype = {
       reset: function TagTree_reset(i, j) {
         var currentLevel = 0, value = 0, level;
         while (currentLevel < this.levels.length) {
           level = this.levels[currentLevel];
           var index = i + j * level.width;
-          if (index in level.items) {
+          if (level.items[index] !== undefined) {
             value = level.items[index];
             break;
           }
           level.index = index;
           i >>= 1;
           j >>= 1;
           currentLevel++;
         }
--- a/browser/extensions/pdfjs/content/web/debugger.js
+++ b/browser/extensions/pdfjs/content/web/debugger.js
@@ -119,18 +119,18 @@ var FontInspector = (function FontInspec
       var download = document.createElement('a');
       if (url) {
         url = /url\(['"]?([^\)"']+)/.exec(url);
         download.href = url[1];
       } else if (fontObj.data) {
         url = URL.createObjectURL(new Blob([fontObj.data], {
           type: fontObj.mimeType
         }));
+        download.href = url;
       }
-      download.href = url;
       download.textContent = 'Download';
       var logIt = document.createElement('a');
       logIt.href = '';
       logIt.textContent = 'Log';
       logIt.addEventListener('click', function(event) {
         event.preventDefault();
         console.log(fontObj);
       });
--- a/browser/extensions/pdfjs/content/web/l10n.js
+++ b/browser/extensions/pdfjs/content/web/l10n.js
@@ -118,16 +118,20 @@
       return gLanguage;
     },
 
     // get the direction (ltr|rtl) of the current language
     getDirection: function() {
       // http://www.w3.org/International/questions/qa-scripts
       // Arabic, Hebrew, Farsi, Pashto, Urdu
       var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
-      return (rtlList.indexOf(gLanguage) >= 0 ? 'rtl' : 'ltr');
+
+      // use the short language code for "full" codes like 'ar-sa' (issue 5440) 
+      var shortCode = gLanguage.split('-')[0];
+
+      return (rtlList.indexOf(shortCode) >= 0) ? 'rtl' : 'ltr';
     },
 
     // translate an element or document fragment
     translate: translateFragment
   };
 })(this);
 
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -188,10 +188,19 @@ functionality specific to firefox. -->
 
 <!ENTITY securityOverride.warningContent "
 <p>You should not add an exception if you are using an internet connection that you do not trust completely or if you are not used to seeing a warning for this server.</p>
 
 <button id='getMeOutOfHereButton'>&securityOverride.getMeOutOfHereButton;</button>
 <button id='exceptionDialogButton'>&securityOverride.exceptionButtonLabel;</button>
 ">
 
+<!ENTITY errorReporting.title "Report this error">
+<!ENTITY errorReporting.longDesc "Reporting the address and certificate information for <span id='hostname'></span> will help us identify and block malicious sites. Thanks for helping create a safer web!">
+<!ENTITY errorReporting.automatic "Automatically report errors in the future">
+<!ENTITY errorReporting.learnMore "Learn more…">
+<!ENTITY errorReporting.sending "Sending report">
+<!ENTITY errorReporting.sent "Report sent">
+<!ENTITY errorReporting.report "Report">
+<!ENTITY errorReporting.tryAgain "Try again">
+
 <!ENTITY remoteXUL.title "Remote XUL">
 <!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
--- a/browser/themes/shared/aboutNetError.css
+++ b/browser/themes/shared/aboutNetError.css
@@ -62,8 +62,80 @@ ul {
 }
 
 /* Pressing the retry button will cause the cursor to flicker from a pointer to
  * not-allowed. Override the disabled cursor behaviour since we will never show
  * the button disabled as the initial state. */
 button:disabled {
   cursor: pointer;
 }
+
+div#certificateErrorReporting {
+  display: none;
+  float:right;
+  /* Align with the "Try Again" button */
+  margin-top:24px;
+  margin-right:24px;
+}
+
+div#certificateErrorReporting a,
+div#certificateErrorReportingPanel a {
+  color: #0095DD;
+}
+
+div#certificateErrorReporting a {
+  text-decoration: none;
+}
+
+div#certificateErrorReporting a:hover {
+  text-decoration: underline;
+}
+
+span.downArrow {
+  font-size: 0.9em;
+}
+
+div#certificateErrorReportingPanel {
+  /* Hidden until the link is clicked */
+  display: none;
+  background-color: white;
+  border: 1px lightgray solid;
+  /* Don't use top padding because the default p style has top padding, and it
+   * makes the overall div look uneven */
+  padding: 0 12px 12px 12px;
+  box-shadow: 0 0 4px #ddd;
+  position: relative;
+  width: 75%;
+  left: 34%;
+  font-size: 0.9em;
+  top: 8px;
+}
+
+span#hostname {
+  font-weight: bold;
+}
+
+#automaticallyReportInFuture {
+  cursor: pointer;
+}
+
+#reportingState {
+  padding-left: 150px;
+}
+
+#reportSendingMessage {
+  position: relative;
+  display: none;
+}
+
+#reportSentMessage {
+  position: relative;
+  display: none;
+}
+
+button#reportCertificateError {
+  position: relative;
+}
+
+button#reportCertificateErrorRetry {
+  position: relative;
+  display: none;
+}
index 508b7defb4479958f4530bcdeb01b63c073be182..5f713fadfc1e41e179804ac58e336e36dfaccf0d
GIT binary patch
literal 65536
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
b0s;a80s;a80s;a80s;a80s;a8Vw(Q}>IkAQ
index f3c610fe83155c083cc23beaf04cb0f7d8e85caa..88d286fa39209ffa2944e2fbacff6fd47e79e6a5
GIT binary patch
literal 106496
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%0D{+bAWIAEU@V_*bd-FY=ub?RX?^J7YV
zInmkN=^HG-8_FhtSIuDBJr^AriN@tXcFShw?^3G)?}83Z_GWqeQgBQB?%mC)OK~nQ
zO==vak;27-2HzhKy`9G`hx^(f^yhBc7ur^IwQmET!{f$(W%Y9DiNGhE{4KA<3!fT;
zpu7uhuR4WY(#e5j${&;l5W~;EJM#w8^UVnh>*f7>%}_|f7g@TKVw(y-!D1zvMPD7~
zxhvq&jmaRBg5u+X_a(7sbRpS$t{R4Nw(nZ4V=N;z!NA<++{5U<{mlX0%(Pg}ZGqqr
zI~jM%#kUt~iK)kK`RByhxkcb#@@+=}$U))kyX6!8rq)^?r?88ir7$t~^YXN3@t$#R
rnV3wJtra_mymoRX7bQW1GmF`H(g#Ki_n#%OpCz!LC9wa~C9wYj{l7qG
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -222,8 +222,10 @@ http://example.fi:80                priv
 https://marketplace.firefox.com:443       privileged
 https://marketplace-dev.allizom.org:443   privileged
 https://marketplace.allizom.org:443       privileged
 
 # Host for HPKP
 https://include-subdomains.pinning-dynamic.example.com:443        privileged,cert=dynamicPinningGood
 https://bad.include-subdomains.pinning-dynamic.example.com:443    privileged,cert=dynamicPinningBad
 
+# Host for static pin tests
+https://include-subdomains.pinning.example.com:443                privileged,cert=staticPinningBad
--- a/config/external/nss/nss.def
+++ b/config/external/nss/nss.def
@@ -141,17 +141,16 @@ CERT_SetOCSPFailureMode
 CERT_SetOCSPTimeout
 CERT_SignedCrlTemplate DATA
 CERT_SignedDataTemplate DATA
 CERT_StartCertExtensions
 CERT_StartCertificateRequestAttributes
 CERT_SubjectPublicKeyInfoTemplate DATA
 CERT_TimeChoiceTemplate DATA
 CERT_VerifyCertificate
-CERT_VerifyCertName
 CERT_VerifySignedDataWithPublicKeyInfo
 DER_AsciiToTime_Util
 DER_DecodeTimeChoice_Util
 DER_Encode
 DER_EncodeTimeChoice_Util
 DER_Encode_Util
 DER_GeneralizedTimeToTime
 DER_GeneralizedTimeToTime_Util
--- a/configure.in
+++ b/configure.in
@@ -46,17 +46,17 @@ dnl ====================================
 _SUBDIR_HOST_CFLAGS="$HOST_CFLAGS"
 _SUBDIR_HOST_CXXFLAGS="$HOST_CXXFLAGS"
 _SUBDIR_HOST_LDFLAGS="$HOST_LDFLAGS"
 _SUBDIR_CONFIG_ARGS="$ac_configure_args"
 
 dnl Set the version number of the libs included with mozilla
 dnl ========================================================
 MOZJPEG=62
-MOZPNG=10613
+MOZPNG=10614
 NSPR_VERSION=4
 NSPR_MINVER=4.10.3
 NSS_VERSION=3
 
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 GLIB_VERSION=1.2.0
 PERL_VERSION=5.006
@@ -9184,19 +9184,19 @@ if test "$MOZ_TREE_FREETYPE"; then
    export ZLIB_CFLAGS="$MOZ_ZLIB_CFLAGS "
    export ZLIB_LIBS="$MOZ_ZLIB_LIBS "
    export CONFIG_FILES="unix-cc.mk:unix-cc.in unix-def.mk:unix-def.in freetype-config freetype2.pc:freetype2.in"
    ac_configure_args="$ac_configure_args --host=$target --disable-shared --with-pic=yes --with-zlib=yes --without-bzip2 --with-png=yes --without-harfbuzz"
 
    if ! test -e modules; then
      mkdir modules
    fi
-   # Only export CC and CXX for the subconfigure, and avoid spilling that
-   # further down the road.
-   (export CC CXX;
+   # Only export CC, CXX and RANLIB for the subconfigure, and avoid spilling
+   # that further down the road.
+   (export CC CXX RANLIB;
     AC_OUTPUT_SUBDIRS(modules/freetype2)
    ) || exit 1
 fi
 
 if test -z "$direct_nspr_config"; then
     dnl ========================================================
     dnl = Setup a nice relatively clean build environment for
     dnl = sub-configures.
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -495,16 +495,23 @@ Element::WrapObject(JSContext *aCx)
           NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
       }
     }
   }
 
   return obj;
 }
 
+/* virtual */
+nsINode*
+Element::GetScopeChainParent() const
+{
+  return OwnerDoc();
+}
+
 nsDOMTokenList*
 Element::ClassList()
 {
   Element::nsDOMSlots* slots = DOMSlots();
 
   if (!slots->mClassList) {
     slots->mClassList = new nsDOMTokenList(this, nsGkAtoms::_class);
   }
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -134,18 +134,18 @@ class AnimationPlayer;
 class Link;
 class UndoManager;
 class DOMRect;
 class DOMRectList;
 class DestinationInsertionPointList;
 
 // IID for the dom::Element interface
 #define NS_ELEMENT_IID \
-{ 0xaa79cb98, 0xc785, 0x44c5, \
-  { 0x80, 0x80, 0x2e, 0x5f, 0x0c, 0xa5, 0xbd, 0x63 } }
+{ 0x31d3f3fb, 0xcdf8, 0x4e40, \
+ { 0xb7, 0x09, 0x1a, 0x11, 0x43, 0x93, 0x61, 0x71 } }
 
 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)
@@ -956,16 +956,18 @@ public:
                            nsIDOMHTMLCollection** aResult);
   nsresult
     GetElementsByClassName(const nsAString& aClassNames,
                            nsIDOMHTMLCollection** aResult);
   void GetClassList(nsISupports** aClassList);
 
   virtual JSObject* WrapObject(JSContext *aCx) MOZ_FINAL MOZ_OVERRIDE;
 
+  nsINode* GetScopeChainParent() const MOZ_OVERRIDE;
+
   /**
    * Locate an nsIEditor rooted at this content node, if there is one.
    */
   nsIEditor* GetEditorInternal();
 
   /**
    * Helper method for NS_IMPL_BOOL_ATTR macro.
    * Gets value of boolean attribute. Only works for attributes in null
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -131,18 +131,18 @@ template<typename> class OwningNonNull;
 template<typename> class Sequence;
 
 template<typename, typename> class CallbackObjectHolder;
 typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0xbab5b447, 0x7e23, 0x4cdd, \
-  { 0xac, 0xe5, 0xaa, 0x04, 0x26, 0x87, 0x2b, 0x97 } }
+{ 0x6bbf1955, 0xd9c4, 0x4d61, \
+ { 0xbf, 0x75, 0x1b, 0xba, 0x55, 0xf7, 0x99, 0xc2 } }
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
   DocumentFlavorSVG, // SVGDocument
   DocumentFlavorPlain, // Just a Document
 };
@@ -2872,12 +2872,16 @@ inline nsINode*
 nsINode::OwnerDocAsNode() const
 {
   return OwnerDoc();
 }
 
 inline mozilla::dom::ParentObject
 nsINode::GetParentObject() const
 {
-  return GetParentObjectInternal(OwnerDoc());
+  mozilla::dom::ParentObject p(OwnerDoc());
+    // Note that mUseXBLScope is a no-op for chrome, and other places where we
+    // don't use XBL scopes.
+  p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree();
+  return p;
 }
 
 #endif /* nsIDocument_h___ */
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -2747,8 +2747,13 @@ nsINode::GetParentElementCrossingShadowR
 
 bool
 nsINode::HasBoxQuadsSupport(JSContext* aCx, JSObject* /* unused */)
 {
   return xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) ||
          Preferences::GetBool("layout.css.getBoxQuads.enabled");
 }
 
+nsINode*
+nsINode::GetScopeChainParent() const
+{
+  return nullptr;
+}
--- a/dom/base/nsINode.h
+++ b/dom/base/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 \
-{ 0x8deda3f4, 0x0f45, 0x497a, \
-  { 0x89, 0x7c, 0xe6, 0x09, 0x12, 0x8a, 0xad, 0xd8 } }
+{ 0x66972940, 0x1d1b, 0x4d15, \
+ { 0x93, 0x11, 0x96, 0x72, 0x84, 0x2e, 0xc7, 0x27 } }
 
 /**
  * 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
 {
@@ -377,31 +377,27 @@ public:
 protected:
   /**
    * WrapNode is called from WrapObject to actually wrap this node, WrapObject
    * does some additional checks and fix-up that's common to all nodes. WrapNode
    * should just call the DOM binding's Wrap function.
    */
   virtual JSObject* WrapNode(JSContext *aCx) = 0;
 
-  // Subclasses that wish to override the parent behavior should return the
-  // result of GetParentObjectIntenral, which handles the XBL scope stuff.
-  //
-  mozilla::dom::ParentObject GetParentObjectInternal(nsINode* aNativeParent) const {
-    mozilla::dom::ParentObject p(aNativeParent);
-    // Note that mUseXBLScope is a no-op for chrome, and other places where we
-    // don't use XBL scopes.
-    p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree();
-    return p;
-  }
-
 public:
   mozilla::dom::ParentObject GetParentObject() const; // Implemented in nsIDocument.h
 
   /**
+   * Return the scope chain parent for this node, for use in things
+   * like event handler compilation.  Returning null means to use the
+   * global object as the scope chain parent.
+   */
+  virtual nsINode* GetScopeChainParent() const;
+
+  /**
    * Return whether the node is an Element node
    */
   bool IsElement() const {
     return GetBoolFlag(NodeIsElement);
   }
 
   /**
    * Return this node as an Element.  Should only be used for nodes
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -22,16 +22,18 @@
 #include "nsPIDOMWindow.h"
 #include "GeckoProfiler.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 #include "nsJSPrincipals.h"
 #include "xpcpublic.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using namespace mozilla::dom;
 
 bool
 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
                               uint32_t* aLineno)
 {
@@ -308,16 +310,37 @@ nsJSUtils::EvaluateString(JSContext* aCx
 {
   EvaluateOptions options;
   options.setNeedResult(false);
   JS::RootedValue unused(aCx);
   return EvaluateString(aCx, aSrcBuf, aScopeObject, aCompileOptions,
                         options, &unused, aOffThreadToken);
 }
 
+/* static */
+bool
+nsJSUtils::GetScopeChainForElement(JSContext* aCx,
+                                   mozilla::dom::Element* aElement,
+                                   JS::AutoObjectVector& aScopeChain)
+{
+  for (nsINode* cur = aElement; cur; cur = cur->GetScopeChainParent()) {
+    JS::RootedValue val(aCx);
+    if (!WrapNewBindingObject(aCx, cur, &val)) {
+      return false;
+    }
+
+    if (!aScopeChain.append(&val.toObject())) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
 //
 // nsDOMJSUtils.h
 //
 
 JSObject* GetDefaultScopeFromJSContext(JSContext *cx)
 {
   // DOM JSContexts don't store their default compartment object on
   // the cx, so in those cases we need to fetch it via the scx
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -20,16 +20,17 @@
 #include "nsString.h"
 
 class nsIScriptContext;
 class nsIScriptGlobalObject;
 
 namespace mozilla {
 namespace dom {
 class AutoJSAPI;
+class Element;
 }
 }
 
 class nsJSUtils
 {
 public:
   static bool GetCallingLocation(JSContext* aContext, const char* *aFilename,
                                  uint32_t* aLineno);
@@ -114,16 +115,21 @@ public:
                                  void **aOffThreadToken = nullptr);
 
   static nsresult EvaluateString(JSContext* aCx,
                                  JS::SourceBufferHolder& aSrcBuf,
                                  JS::Handle<JSObject*> aScopeObject,
                                  JS::CompileOptions &aCompileOptions,
                                  void **aOffThreadToken = nullptr);
 
+  // Returns false if an exception got thrown on aCx.  Passing a null
+  // aElement is allowed; that wil produce an empty aScopeChain.
+  static bool GetScopeChainForElement(JSContext* aCx,
+                                      mozilla::dom::Element* aElement,
+                                      JS::AutoObjectVector& aScopeChain);
 };
 
 class MOZ_STACK_CLASS AutoDontReportUncaught {
   JSContext* mContext;
   bool mWasSet;
 
 public:
   explicit AutoDontReportUncaught(JSContext* aContext) : mContext(aContext) {
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -339,17 +339,17 @@ skip-if = buildapp == 'b2g' || e10s # b2
 [test_XHR_header.html]
 [test_XHR_onuploadprogress.html]
 [test_XHR_parameters.html]
 skip-if = buildapp == 'b2g' # b2g(86 total, 4 failing - testing mozAnon - got false, expected true) b2g-debug(86 total, 4 failing - testing mozAnon - got false, expected true) b2g-desktop(86 total, 4 failing - testing mozAnon - got false, expected true)
 [test_XHR_system.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(12 total, 2 failing - .mozSystem == true - got false, expected true + ) b2g-desktop(12 total, 2 failing - .mozSystem == true - got false, expected true + )
 [test_XHR_timeout.html]
 skip-if = buildapp == 'b2g' # b2g(flaky on B2G, bug 960743) b2g-debug(flaky on B2G, bug 960743) b2g-desktop(flaky on B2G, bug 960743)
-[test_XHR_timeout.js]
+support-files = test_XHR_timeout.js
 [test_base.xhtml]
 [test_blobconstructor.html]
 [test_bug166235.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_bug199959.html]
 [test_bug218236.html]
 [test_bug218277.html]
 [test_bug238409.html]
@@ -385,17 +385,17 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_bug345339.html]
 skip-if = e10s # Bug 1081453 - shutdown leaks with e10s and WebIDL dom::File
 [test_bug346485.html]
 [test_bug352728.html]
 [test_bug352728.xhtml]
 [test_bug353334.html]
 [test_bug355026.html]
 [test_bug357450.html]
-[test_bug357450.js]
+support-files = test_bug357450.js
 [test_bug357450.xhtml]
 [test_bug357450_svg.xhtml]
 [test_bug357509.html]
 [test_bug358660.html]
 [test_bug362391.xhtml]
 [test_bug364092.xhtml]
 [test_bug364413.xhtml]
 [test_bug366944.html]
@@ -408,32 +408,32 @@ skip-if = e10s # Bug 1081453 - shutdown 
 [test_bug371576-5.html]
 [test_bug372086.html]
 [test_bug372964-2.html]
 [test_bug372964.html]
 [test_bug373181.xhtml]
 [test_bug375314.html]
 [test_bug378969.html]
 [test_bug380418.html]
-[test_bug380418.html^headers^]
+support-files = test_bug380418.html^headers^
 [test_bug382113.html]
 skip-if = (os == 'mac' || os == 'win') && debug # bug 453969
 [test_bug382871.html]
 [test_bug384003.xhtml]
 [test_bug390219.html]
 [test_bug390735.html]
 [test_bug392318.html]
 [test_bug392511.html]
 [test_bug393968.html]
 [test_bug395915.html]
 [test_bug397234.html]
 [test_bug398243.html]
 [test_bug401662.html]
 [test_bug402150.html]
-[test_bug402150.html^headers^]
+support-files = test_bug402150.html^headers^
 [test_bug403841.html]
 [test_bug403852.html]
 skip-if = e10s
 [test_bug403868.xml]
 [test_bug405182.html]
 [test_bug409380.html]
 [test_bug410229.html]
 [test_bug413974.html]
@@ -502,17 +502,17 @@ skip-if = buildapp == 'b2g'
 [test_bug473162-1.html]
 [test_bug473162-2.html]
 [test_bug475156.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 855762 # b2g(36 total - bug 902611) b2g-debug(36 total - bug 902611) b2g-desktop(36 total - bug 902611)
 [test_bug482935.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 855762
 [test_bug484396.html]
 [test_bug493881.html]
-[test_bug493881.js]
+support-files = test_bug493881.js
 [test_bug498240.html]
 [test_bug498433.html]
 skip-if = buildapp == 'b2g'
 [test_bug498897.html]
 [test_bug499656.html]
 [test_bug499656.xhtml]
 [test_bug500937.html]
 [test_bug503481.html]
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1499,44 +1499,27 @@ WrapNativeParent(JSContext* cx, T* p, ns
 // things like the nsWrapperCache for it.
 template<typename T>
 static inline JSObject*
 WrapNativeParent(JSContext* cx, const T& p)
 {
   return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
 }
 
-// A way to differentiate between nodes, which use the parent object
-// returned by native->GetParentObject(), and all other objects, which
-// just use the parent's global.
-static inline JSObject*
-GetRealParentObject(void* aParent, JSObject* aParentObject)
-{
-  return aParentObject ?
-    js::GetGlobalForObjectCrossCompartment(aParentObject) : nullptr;
-}
-
-static inline JSObject*
-GetRealParentObject(Element* aParent, JSObject* aParentObject)
-{
-  return aParentObject;
-}
-
 HAS_MEMBER(GetParentObject)
 
 template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
 struct GetParentObject
 {
   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
   {
     MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
     T* native = UnwrapDOMObject<T>(obj);
-    return
-      GetRealParentObject(native,
-                          WrapNativeParent(cx, native->GetParentObject()));
+    JSObject* wrappedParent = WrapNativeParent(cx, native->GetParentObject());
+    return wrappedParent ? js::GetGlobalForObjectCrossCompartment(wrappedParent) : nullptr;
   }
 };
 
 template<typename T>
 struct GetParentObject<T, false>
 {
   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
   {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3064,51 +3064,49 @@ class CGConstructorEnabled(CGAbstractMet
                                         pre="return ", post=";\n", reindent=True)
         else:
           conditionsWrapper = CGGeneric("return true;\n")
 
         body.append(conditionsWrapper)
         return body.define()
 
 
-def CreateBindingJSObject(descriptor, properties, parent):
+def CreateBindingJSObject(descriptor, properties):
     # We don't always need to root obj, but there are a variety
     # of cases where we do, so for simplicity, just always root it.
     objDecl = "JS::Rooted<JSObject*> obj(aCx);\n"
     if descriptor.proxy:
-        create = fill(
+        create = dedent(
             """
             JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aObject));
             js::ProxyOptions options;
             options.setClass(&Class.mBase);
             obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
-                                 proxyPrivateVal, proto, ${parent}, options);
+                                 proxyPrivateVal, proto, global, options);
             if (!obj) {
               return nullptr;
             }
 
-            """,
-            parent=parent)
+            """)
         if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
             create += dedent("""
                 js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO,
                                   JS::PrivateValue(&aObject->mExpandoAndGeneration));
 
                 """)
     else:
-        create = fill(
-            """
-            obj = JS_NewObject(aCx, Class.ToJSClass(), proto, ${parent});
+        create = dedent(
+            """
+            obj = JS_NewObject(aCx, Class.ToJSClass(), proto, global);
             if (!obj) {
               return nullptr;
             }
 
             js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
-            """,
-            parent=parent)
+            """)
     create = objDecl + create
 
     if descriptor.nativeOwnership == 'refcounted':
         create += "NS_ADDREF(aObject);\n"
     else:
         create += dedent("""
             // Make sure the native objects inherit from NonRefcountedDOMObject so that we
             // log their ctor and dtor.
@@ -3249,51 +3247,48 @@ class CGWrapWithCacheMethod(CGAbstractMe
     def definition_body(self):
         return fill(
             """
             $*{assertion}
 
             MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
                        "nsISupports must be on our primary inheritance chain");
 
-            JS::Rooted<JSObject*> parent(aCx,
-              GetRealParentObject(aObject,
-                                  WrapNativeParent(aCx, aObject->GetParentObject())));
+            JS::Rooted<JSObject*> parent(aCx, WrapNativeParent(aCx, aObject->GetParentObject()));
             if (!parent) {
               return nullptr;
             }
 
             // That might have ended up wrapping us already, due to the wonders
             // of XBL.  Check for that, and bail out as needed.  Scope so we don't
             // collide with the "obj" we declare in CreateBindingJSObject.
             {
               JSObject* obj = aCache->GetWrapper();
               if (obj) {
                 return obj;
               }
             }
 
             JSAutoCompartment ac(aCx, parent);
-            JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, parent));
+            JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(parent));
             JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
             if (!proto) {
               return nullptr;
             }
 
-            $*{parent}
+            $*{createObject}
 
             $*{unforgeable}
 
             aCache->SetWrapper(obj);
             $*{slots}
             return obj;
             """,
             assertion=AssertInheritanceChain(self.descriptor),
-            parent=CreateBindingJSObject(self.descriptor, self.properties,
-                                         "parent"),
+            createObject=CreateBindingJSObject(self.descriptor, self.properties),
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, True))
 
 
 class CGWrapMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
@@ -3329,26 +3324,25 @@ class CGWrapNonWrapperCacheMethod(CGAbst
             $*{assertions}
 
             JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
             JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
             if (!proto) {
               return nullptr;
             }
 
-            $*{global_}
+            $*{createObject}
 
             $*{unforgeable}
 
             $*{slots}
             return obj;
             """,
             assertions=AssertInheritanceChain(self.descriptor),
-            global_=CreateBindingJSObject(self.descriptor, self.properties,
-                                          "global"),
+            createObject=CreateBindingJSObject(self.descriptor, self.properties),
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, False))
 
 
 class CGWrapGlobalMethod(CGAbstractMethod):
     """
     Create a wrapper JSObject for a global.  The global must implement
     nsWrapperCache.
--- a/dom/encoding/moz.build
+++ b/dom/encoding/moz.build
@@ -30,12 +30,11 @@ GENERATED_FILES += [
     'encodingsgroups.properties.h',
     'labelsencodings.properties.h',
     'localesfallbacks.properties.h',
     'nonparticipatingdomains.properties.h',
 ]
 
 MOCHITEST_MANIFESTS += [
     'test/mochitest.ini',
-    'test/unit/mochitest.ini',
 ]
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
--- a/dom/encoding/test/mochitest.ini
+++ b/dom/encoding/test/mochitest.ini
@@ -4,20 +4,26 @@ support-files =
   file_utf16_be_bom.css
   file_utf16_be_bom.js
   file_utf16_be_bom.xhtml
   file_utf16_le_bom.css
   file_utf16_le_bom.js
   file_utf16_le_bom.xhtml
   file_utf16_le_nobom.xhtml
   file_TLD.html
+  unit/test_big5.js
+  unit/test_euc-jp.js
+  unit/test_euc-kr.js
+  unit/test_gbk.js
+  unit/test_iso-2022-jp.js
+  unit/test_shift_jis.js
   worker_helper.js
+  test_BOMEncoding.js
+  test_TextDecoder.js
+  test_TextEncoder.js
 
-[test_BOMEncoding.js]
 [test_TextDecoder.html]
-[test_TextDecoder.js]
 [test_TextEncoder.html]
-[test_TextEncoder.js]
 [test_stringencoding.html]
 skip-if = buildapp == 'b2g' # b2g(Test timed out on b2g board) b2g-debug(Test timed out on b2g board) b2g-desktop(Test timed out on b2g board)
 [test_submit_euckr.html]
 [test_TLD.html]
 [test_utf16_files.html]
deleted file mode 100644
--- a/dom/encoding/test/unit/mochitest.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[DEFAULT]
-skip-if = e10s
-
-[test_big5.js]
-[test_euc-jp.js]
-[test_euc-kr.js]
-[test_gbk.js]
-[test_iso-2022-jp.js]
-[test_shift_jis.js]
deleted file mode 100644
--- a/dom/encoding/test/unit/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-MOCHITEST_MANIFESTS += ['mochitest.ini']
-
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -858,50 +858,43 @@ EventListenerManager::CompileEventHandle
     JSAutoCompartment ac(cx, wrapScope);
     nsresult rv = nsContentUtils::WrapNative(cx, mTarget, &v,
                                              /* aAllowWrapping = */ false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  JS::AutoObjectVector scopeChain(cx);
-  { // scope for curScope
-    // We append all the non-globals on our desired scope chain.
-    JS::Rooted<JSObject*> curScope(cx, &v.toObject());
-    while (curScope && !JS_IsGlobalObject(curScope)) {
-      if (!scopeChain.append(curScope)) {
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-      curScope = JS_GetParent(curScope);
-    }
-  }
-
   if (addonId) {
     JS::Rooted<JSObject*> vObj(cx, &v.toObject());
     JS::Rooted<JSObject*> addonScope(cx, xpc::GetAddonScope(cx, vObj, addonId));
     if (!addonScope) {
       return NS_ERROR_FAILURE;
     }
     JSAutoCompartment ac(cx, addonScope);
-    for (size_t i = 0; i < scopeChain.length(); ++i) {
-      if (!JS_WrapObject(cx, scopeChain[i])) {
-        return NS_ERROR_FAILURE;
-      }
-    }
 
-    // And wrap v as well, since scopeChain might be empty so we can't
-    // reliably use it to enter a compartment.
+    // Wrap our event target into the addon scope, since that's where we want to
+    // do all our work.
     if (!JS_WrapValue(cx, &v)) {
       return NS_ERROR_FAILURE;
     }
   }
   JS::Rooted<JSObject*> target(cx, &v.toObject());
   JSAutoCompartment ac(cx, target);
 
+  // Now that we've entered the compartment we actually care about, create our
+  // scope chain.  Note that we start with |element|, not aElement, because
+  // mTarget is different from aElement in the <body> case, where mTarget is a
+  // Window, and in that case we do not want the scope chain to include the body
+  // or the document.
+  JS::AutoObjectVector scopeChain(cx);
+  if (!nsJSUtils::GetScopeChainForElement(cx, element, scopeChain)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
   nsDependentAtomString str(attrName);
   // Most of our names are short enough that we don't even have to malloc
   // the JS string stuff, so don't worry about playing games with
   // refcounting XPCOM stringbuffers.
   JS::Rooted<JSString*> jsStr(cx, JS_NewUCStringCopyN(cx,
                                                       str.BeginReading(),
                                                       str.Length()));
   NS_ENSURE_TRUE(jsStr, NS_ERROR_OUT_OF_MEMORY);
@@ -910,18 +903,17 @@ EventListenerManager::CompileEventHandle
   if (NS_WARN_IF(!WrapNewBindingObject(cx, target, aElement, &v))) {
     return NS_ERROR_FAILURE;
   }
   JS::CompileOptions options(cx);
   options.setIntroductionType("eventHandler")
          .setFileAndLine(url.get(), lineNo)
          .setVersion(JSVERSION_DEFAULT)
          .setElement(&v.toObject())
-         .setElementAttributeName(jsStr)
-         .setDefineOnScope(false);
+         .setElementAttributeName(jsStr);
 
   JS::Rooted<JSObject*> handler(cx);
   result = nsJSUtils::CompileFunction(jsapi, scopeChain, options,
                                       nsAtomCString(typeAtom),
                                       argCount, argNames, *body, handler.address());
   NS_ENSURE_SUCCESS(result, result);
   NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
 
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -22,18 +22,18 @@ skip-if = buildapp == 'b2g'
 skip-if = buildapp == 'b2g'
 [test_bug288392.html]
 [test_bug299673-1.html]
 [test_bug1037990.html]
 [test_bug299673-2.html]
 [test_bug322588.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 [test_bug328885.html]
-[test_bug336682.js]
 [test_bug336682_1.html]
+support-files = test_bug336682.js
 [test_bug367781.html]
 [test_bug368835.html]
 [test_bug379120.html]
 [test_bug391568.xhtml]
 [test_bug402089.html]
 [test_bug405632.html]
 [test_bug409604.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
--- a/dom/html/HTMLLegendElement.cpp
+++ b/dom/html/HTMLLegendElement.cpp
@@ -17,17 +17,17 @@ namespace dom {
 
 HTMLLegendElement::~HTMLLegendElement()
 {
 }
 
 NS_IMPL_ELEMENT_CLONE(HTMLLegendElement)
 
 nsIContent*
-HTMLLegendElement::GetFieldSet()
+HTMLLegendElement::GetFieldSet() const
 {
   nsIContent* parent = GetParent();
 
   if (parent && parent->IsHTML(nsGkAtoms::fieldset)) {
     return parent;
   }
 
   return nullptr;
--- a/dom/html/HTMLLegendElement.h
+++ b/dom/html/HTMLLegendElement.h
@@ -49,17 +49,17 @@ public:
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) MOZ_OVERRIDE;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const MOZ_OVERRIDE;
 
-  Element* GetFormElement()
+  Element* GetFormElement() const
   {
     nsCOMPtr<nsIFormControl> fieldsetControl = do_QueryInterface(GetFieldSet());
 
     return fieldsetControl ? fieldsetControl->GetFormElement() : nullptr;
   }
 
   /**
    * WebIDL Interface
@@ -72,30 +72,30 @@ public:
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
 
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
 
-  ParentObject GetParentObject() {
+  nsINode* GetScopeChainParent() const MOZ_OVERRIDE
+  {
     Element* form = GetFormElement();
-    return form ? GetParentObjectInternal(form)
-                : nsGenericHTMLElement::GetParentObject();
+    return form ? form : nsGenericHTMLElement::GetScopeChainParent();
   }
 
 protected:
   virtual ~HTMLLegendElement();
 
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 
   /**
    * Get the fieldset content element that contains this legend.
    * Returns null if there is no fieldset containing this legend.
    */
-  nsIContent* GetFieldSet();
+  nsIContent* GetFieldSet() const;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLLegendElement_h */
--- a/dom/html/ImageDocument.cpp
+++ b/dom/html/ImageDocument.cpp
@@ -776,17 +776,17 @@ ImageDocument::UpdateTitleAndCharset()
   static const char* const formatNames[4] = 
   {
     "ImageTitleWithNeitherDimensionsNorFile",
     "ImageTitleWithoutDimensions",
     "ImageTitleWithDimensions2",
     "ImageTitleWithDimensions2AndFile",
   };
 
-  MediaDocument::UpdateTitleAndCharset(typeStr, formatNames,
+  MediaDocument::UpdateTitleAndCharset(typeStr, mChannel, formatNames,
                                        mImageWidth, mImageHeight, status);
 }
 
 void
 ImageDocument::ResetZoomLevel()
 {
   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
   if (docShell) {
--- a/dom/html/MediaDocument.cpp
+++ b/dom/html/MediaDocument.cpp
@@ -273,20 +273,26 @@ MediaDocument::StartLayout()
     nsresult rv = shell->Initialize(visibleArea.width, visibleArea.height);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 void
-MediaDocument::GetFileName(nsAString& aResult)
+MediaDocument::GetFileName(nsAString& aResult, nsIChannel* aChannel)
 {
   aResult.Truncate();
 
+  if (aChannel) {
+    aChannel->GetContentDispositionFilename(aResult);
+    if (!aResult.IsEmpty())
+      return;
+  }
+
   nsCOMPtr<nsIURL> url = do_QueryInterface(mDocumentURI);
   if (!url)
     return;
 
   nsAutoCString fileName;
   url->GetFileName(fileName);
   if (fileName.IsEmpty())
     return;
@@ -334,22 +340,23 @@ MediaDocument::LinkStylesheet(const nsAS
   link->SetAttr(kNameSpaceID_None, nsGkAtoms::href, aStylesheet, true);
 
   Element* head = GetHeadElement();
   return head->AppendChildTo(link, false);
 }
 
 void 
 MediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
+                                     nsIChannel* aChannel,
                                      const char* const* aFormatNames,
                                      int32_t aWidth, int32_t aHeight,
                                      const nsAString& aStatus)
 {
   nsXPIDLString fileStr;
-  GetFileName(fileStr);
+  GetFileName(fileStr, aChannel);
 
   NS_ConvertASCIItoUTF16 typeStr(aTypeStr);
   nsXPIDLString title;
 
   if (mStringBundle) {
     // if we got a valid size (not all media have a size)
     if (aWidth != 0 && aHeight != 0) {
       nsAutoString widthStr;
--- a/dom/html/MediaDocument.h
+++ b/dom/html/MediaDocument.h
@@ -43,32 +43,33 @@ public:
 protected:
   void BecomeInteractive();
 
   virtual nsresult CreateSyntheticDocument();
 
   friend class MediaDocumentStreamListener;
   nsresult StartLayout();
 
-  void GetFileName(nsAString& aResult);
+  void GetFileName(nsAString& aResult, nsIChannel* aChannel);
 
   nsresult LinkStylesheet(const nsAString& aStylesheet);
 
   // |aFormatNames[]| needs to have four elements in the following order: 
   // a format name with neither dimension nor file, a format name with
   // filename but w/o dimension, a format name with dimension but w/o filename,
   // a format name with both of them.  For instance, it can have
   // "ImageTitleWithNeitherDimensionsNorFile", "ImageTitleWithoutDimensions",
   // "ImageTitleWithDimesions2",  "ImageTitleWithDimensions2AndFile".
   //
   // Also see MediaDocument.properties if you want to define format names
   // for a new subclass. aWidth and aHeight are pixels for |ImageDocument|,
   // but could be in other units for other 'media', in which case you have to 
   // define format names accordingly. 
   void UpdateTitleAndCharset(const nsACString&  aTypeStr,
+                             nsIChannel* aChannel,
                              const char* const* aFormatNames = sFormatNames,
                              int32_t            aWidth = 0,
                              int32_t            aHeight = 0,
                              const nsAString&   aStatus = EmptyString());
 
   nsCOMPtr<nsIStringBundle>     mStringBundle;
   static const char* const      sFormatNames[4];
   
--- a/dom/html/PluginDocument.cpp
+++ b/dom/html/PluginDocument.cpp
@@ -180,17 +180,17 @@ PluginDocument::StartDocumentLoad(const 
     return rv;
   }
 
   rv = aChannel->GetContentType(mMimeType);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  MediaDocument::UpdateTitleAndCharset(mMimeType);
+  MediaDocument::UpdateTitleAndCharset(mMimeType, aChannel);
 
   mStreamListener = new PluginStreamListener(this);
   NS_ASSERTION(aDocListener, "null aDocListener");
   NS_ADDREF(*aDocListener = mStreamListener);
 
   return rv;
 }
 
--- a/dom/html/VideoDocument.cpp
+++ b/dom/html/VideoDocument.cpp
@@ -123,17 +123,17 @@ VideoDocument::CreateSyntheticVideoDocum
 
 void
 VideoDocument::UpdateTitle(nsIChannel* aChannel)
 {
   if (!aChannel)
     return;
 
   nsAutoString fileName;
-  GetFileName(fileName);
+  GetFileName(fileName, aChannel);
   SetTitle(fileName);
 }
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult
 NS_NewVideoDocument(nsIDocument** aResult)
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1891,24 +1891,20 @@ nsGenericHTMLFormElement::~nsGenericHTML
   // Check that this element doesn't know anything about its form at this point.
   NS_ASSERTION(!mForm, "mForm should be null at this point!");
 }
 
 NS_IMPL_ISUPPORTS_INHERITED(nsGenericHTMLFormElement,
                             nsGenericHTMLElement,
                             nsIFormControl)
 
-mozilla::dom::ParentObject
-nsGenericHTMLFormElement::GetParentObject() const
+nsINode*
+nsGenericHTMLFormElement::GetScopeChainParent() const
 {
-  // We use the parent chain to implement the scope for event handlers.
-  if (mForm) {
-    return GetParentObjectInternal(mForm);
-  }
-  return nsGenericHTMLElement::GetParentObject();
+  return mForm ? mForm : nsGenericHTMLElement::GetScopeChainParent();
 }
 
 bool
 nsGenericHTMLFormElement::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eCONTENT | eHTML_FORM_CONTROL));
 }
 
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -1240,17 +1240,17 @@ ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPE
 class nsGenericHTMLFormElement : public nsGenericHTMLElement,
                                  public nsIFormControl
 {
 public:
   explicit nsGenericHTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  mozilla::dom::ParentObject GetParentObject() const;
+  nsINode* GetScopeChainParent() const MOZ_OVERRIDE;
 
   virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
   virtual void SaveSubtreeState() MOZ_OVERRIDE;
 
   // nsIFormControl
   virtual mozilla::dom::HTMLFieldSetElement* GetFieldSet();
   virtual mozilla::dom::Element* GetFormElement() MOZ_OVERRIDE;
   mozilla::dom::HTMLFormElement* GetForm() const
deleted file mode 100644
--- a/dom/html/test/imports/file_cycle_5_A.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_B.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_D.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("A");
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/html/test/imports/file_cycle_5_B.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_D.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("B");
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/html/test/imports/file_cycle_5_C.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_B.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_D.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("C");
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/html/test/imports/file_cycle_5_D.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_B.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("D");
-  </script>
-</body>
-</html>
new file mode 100644
--- /dev/null
+++ b/dom/html/test/imports/file_simple_import.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<head>
+</head>
+<body>Simple import</body>
\ No newline at end of file
--- a/dom/html/test/imports/mochitest.ini
+++ b/dom/html/test/imports/mochitest.ini
@@ -26,25 +26,21 @@ support-files =
   file_cycle_3_A.html
   file_cycle_3_B.html
   file_cycle_3_C.html
   file_cycle_4_A.html
   file_cycle_4_B.html
   file_cycle_4_C.html
   file_cycle_4_D.html
   file_cycle_4_E.html
-  file_cycle_5_A.html
-  file_cycle_5_B.html
-  file_cycle_5_C.html
-  file_cycle_5_D.html
   file_encoding.html
+  file_simple_import.html
 
 [test_cycle_1.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_cycle_2.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_cycle_3.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_cycle_4.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
-[test_cycle_5.html]
-skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_encoding.html]
+[test_defaultView.html]
deleted file mode 100644
--- a/dom/html/test/imports/test_cycle_5.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1061469
--->
-<head>
-  <title>Test for Bug 1061469</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
-</head>
-<body>
-  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061469">Mozilla Bug 1061469</a>
-  <script type="text/javascript">
-    SimpleTest.waitForExplicitFinish();
-    var counter = 0;
-    var fcounter = 0;
-    var order = [];
-    function loaded() {
-      counter++;
-    }
-    function failed() {
-      fcounter++;
-    }
-  </script>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-  <script type="text/javascript">
-    is(counter, 14, "Imports are loaded");
-    is(fcounter, 0, "No error in imports");
-    var expected = ["D","C","B","A"];
-    for (i in expected)
-      is(order[i], expected[i], "import " + i + " should be " + expected[i]);
-    SimpleTest.finish();
-  </script>
-</body>
-</html>
new file mode 100644
--- /dev/null
+++ b/dom/html/test/imports/test_defaultView.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1061469
+-->
+<head>
+  <title>Test for Bug 1061469</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+</head>
+<body>
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061469">Mozilla Bug 1061469</a>
+  <script type="text/javascript">
+    SimpleTest.waitForExplicitFinish();
+    var success = false;
+    function loaded() {
+      success = true;
+    }
+    function failed() {
+      ok(false, "Import loading failed");
+    }
+  </script>
+  <link rel="import" href="file_simple_import.html" id="import" onload="loaded()" onerror="failed()"></link>
+  <script type="text/javascript">
+    document.defaultView;
+    is(document.getElementById("import").import.defaultView, null, "defaultView is always null for imports");
+    SimpleTest.finish();
+  </script>
+</body>
+</html>
\ No newline at end of file
--- a/dom/inputmethod/mochitest/mochitest.ini
+++ b/dom/inputmethod/mochitest/mochitest.ini
@@ -16,13 +16,12 @@ support-files =
 [test_bug949059.html]
 [test_bug953044.html]
 [test_bug960946.html]
 [test_bug978918.html]
 [test_bug1026997.html]
 [test_bug1043828.html]
 [test_bug1059163.html]
 [test_bug1066515.html]
-[test_delete_focused_element.html]
 [test_sendkey_cancel.html]
 [test_sync_edit.html]
 [test_two_inputs.html]
 [test_two_selects.html]
deleted file mode 100644
--- a/dom/inputmethod/mochitest/test_delete_focused_element.html
+++ /dev/null
@@ -1,112 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=952741
--->
-<head>
-  <title>Test focused element deletion for InputMethod API.</title>
-  <script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=952741">Mozilla Bug 952741</a>
-<input type="text" />
-<p id="display"></p>
-<pre id="test">
-<script class="testbody" type="application/javascript;version=1.7">
-
-inputmethod_setup(function() {
-  runTest();
-});
-
-// The frame script running in file_test_app.html.
-function appFrameScript() {
-  let input = content.document.getElementById('test-input');
-  let textarea = content.document.createElement('textarea');
-  textarea.lang = 'en';
-
-  content.document.body.appendChild(textarea);
-
-  textarea.onfocus = function() {
-    content.setTimeout(function() {
-      textarea.parentNode.removeChild(textarea);
-      sendAsyncMessage('test:InputMethod:finished', {});
-    }, 10);
-  };
-
-  content.setTimeout(function() {
-    content.setTimeout(function() {
-      textarea.focus();
-    }, 10);
-
-    input.parentNode.removeChild(input);
-  }, 0);
-}
-
-function runTest() {
-  var timeoutId = null;
-
-  // Create an app frame to recieve keyboard inputs.
-  let app = document.createElement('iframe');
-  app.src = 'file_test_app.html';
-  app.setAttribute('mozbrowser', true);
-  document.body.appendChild(app);
-  app.addEventListener('mozbrowserloadend', function() {
-    let mm = SpecialPowers.getBrowserFrameMessageManager(app);
-    mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
-    mm.addMessageListener("test:InputMethod:finished", function() {
-      timeoutId = setTimeout(function() {
-        ok(false, 'No inputcontextchange event when textarea is deleted.');
-        inputmethod_cleanup();
-      }, 20000);
-    });
-  });
-
-  let im = navigator.mozInputMethod;
-  let count = 0;
-  im.oninputcontextchange = function() {
-    switch (count++) {
-      case 0:
-        if (!im.inputcontext) {
-          break;
-        }
-        is(im.inputcontext.lang, 'zh', 'input was focused.');
-        return;
-      case 1:
-        if (im.inputcontext) {
-          break;
-        }
-        ok(true, 'input was blurred.');
-        return;
-      case 2:
-        if (!im.inputcontext) {
-          break;
-        }
-        is(im.inputcontext.lang, 'en', 'textarea was focused.');
-        return;
-      case 3:
-        if (im.inputcontext) {
-          break;
-        }
-        ok(true, 'textarea was removed.');
-        clearTimeout(timeoutId);
-        inputmethod_cleanup();
-        return;
-      default:
-        return;
-    }
-    count = 100;
-    ok(false, 'Should not arrive here.');
-    inputmethod_cleanup();
-  };
-
-  // Set current page as an input method.
-  SpecialPowers.wrap(im).setActive(true);
-}
-
-</script>
-</pre>
-</body>
-</html>
-
--- a/dom/inputmethod/mochitest/test_two_inputs.html
+++ b/dom/inputmethod/mochitest/test_two_inputs.html
@@ -1,21 +1,23 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=1057898
+https://bugzilla.mozilla.org/show_bug.cgi?id=952741
 -->
 <head>
   <title>Test switching between two inputs</title>
   <script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1057898">Mozilla Bug 1057898</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=952741">Mozilla Bug 952741</a>
 <p id="display"></p>
 <pre id="test">
 <script class="testbody" type="application/javascript;version=1.7">
 
 inputmethod_setup(function() {
   runTest();
 });
 
@@ -50,17 +52,27 @@ let appFrameScript = function appFrameSc
         input2.focus();
         input2.blur();
 
         input1.focus();
 
         break;
 
       case 6:
-        input1.blur();
+        content.document.body.removeChild(input1);
+
+        break;
+
+      case 7:
+        input2.focus();
+
+        break;
+
+      case 8:
+        content.document.body.removeChild(input2);
 
         break;
     }
   });
 };
 
 function runTest() {
   let im = navigator.mozInputMethod;
@@ -109,20 +121,35 @@ function runTest() {
       // focus on the first input receives the first input context.
       case 5:
         ok(!!inputcontext, 'Receving the first input context');
         is(inputcontext.textAfterCursor, 'First');
 
         mm.sendAsyncMessage('test:next');
         break;
 
-      // blur on the first input results null input context
+      // remove on the first focused input results null input context
       case 6:
         is(inputcontext, null, 'Receving null inputcontext');
 
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // input context for the second input.
+      case 7:
+        ok(!!inputcontext, 'Receving the second input context');
+        is(inputcontext.textAfterCursor, 'Second');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // remove on the second focused input results null input context
+      case 8:
+        is(inputcontext, null, 'Receving null inputcontext');
+
         inputmethod_cleanup();
         break;
 
       default:
         ok(false, 'Receving extra inputcontextchange calls');
         inputmethod_cleanup();
 
         break;
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -337,17 +337,16 @@ skip-if = (toolkit == 'android' && proce
 [test_bug957847.html]
 [test_bug1018933.html]
 [test_can_play_type.html]
 [test_can_play_type_mpeg.html]
 skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') # bug 1021675 #x86 only bug 914439
 [test_can_play_type_no_ogg.html]
 [test_can_play_type_ogg.html]
 [test_chaining.html]
-skip-if = toolkit == 'gonk' && debug
 [test_clone_media_element.html]
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
 [test_closing_connections.html]
 [test_constants.html]
 [test_contentDuration1.html]
 [test_contentDuration2.html]
 [test_contentDuration3.html]
 [test_contentDuration4.html]
--- a/dom/tests/browser/browser_bug1008941_dismissGeolocationHanger.js
+++ b/dom/tests/browser/browser_bug1008941_dismissGeolocationHanger.js
@@ -30,32 +30,30 @@ add_task(function testDismissHanger() {
 
 add_task(function asyncCleanup() {
   // close the tab
   gBrowser.removeTab(gBrowser.selectedTab);
   info("Cleanup: Closed the tab");
 });
 
 function waitForPageLoad(aTab) {
-  let deferred = Promise.defer();
+  return new Promise(resolve => {
+    function onTabLoad(event) {
+      aTab.linkedBrowser.removeEventListener("load", onTabLoad, true);
+      info("Load tab event received");
+      resolve();
+    };
 
-  function onTabLoad(event) {
-    aTab.linkedBrowser.removeEventListener("load", onTabLoad, true);
-    info("Load tab event received");
-    deferred.resolve();
-  }
-
-  aTab.linkedBrowser.addEventListener("load", onTabLoad, true, true);
-  return deferred.promise;
+    aTab.linkedBrowser.addEventListener("load", onTabLoad, true, true);
+  });
 }
 
 function waitForPanelShow(aPanel) {
-  let deferred = Promise.defer();
+  return new Promise(resolve => {
+    function onPopupShown(event) {
+      PopupNotifications.panel.removeEventListener("popupshown", onPopupShown, true);
+      info("Popup shown event received");
+      resolve();
+    }
 
-  function onPopupShown(event) {
-    PopupNotifications.panel.removeEventListener("popupshown", onPopupShown, true);
-    info("Popup shown event received");
-    deferred.resolve();
-  }
-
-  PopupNotifications.panel.addEventListener("popupshown", onPopupShown, true, true);
-  return deferred.promise;
+    PopupNotifications.panel.addEventListener("popupshown", onPopupShown, true, true);
+  });
 }
--- a/dom/tests/mochitest/ajax/mochikit/tests/mochitest.ini
+++ b/dom/tests/mochitest/ajax/mochikit/tests/mochitest.ini
@@ -18,18 +18,17 @@ support-files =
   MochiKit-Style.html
   MochiKit-Visual.html
   cli.js
   index.html
   standalone.js
   SimpleTest/SimpleTest.js
   SimpleTest/TestRunner.js
   SimpleTest/test.css
-
-[test_Base.js]
-[test_Color.js]
-[test_DateTime.js]
-[test_DragAndDrop.js]
-[test_Format.js]
-[test_Iter.js]
-[test_Logging.js]
-[test_MochiKit-Async.json]
-[test_Signal.js]
+  test_Base.js
+  test_Color.js
+  test_DateTime.js
+  test_DragAndDrop.js
+  test_Format.js
+  test_Iter.js
+  test_Logging.js
+  test_MochiKit-Async.json
+  test_Signal.js
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -65,17 +65,17 @@ skip-if = e10s || buildapp == 'mulet' ||
 [test_idleapi_permissions.html]
 skip-if = e10s || buildapp == 'b2g' || buildapp == 'mulet'
 [test_img_mutations.html]
 [test_interfaces.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 # [test_network_events.html]
 # Disable this test until bug 795711 is fixed.
 [test_offsets.html]
-[test_offsets.js]
+support-files = test_offsets.js
 [test_outerHTML.html]
 [test_outerHTML.xhtml]
 skip-if = buildapp == 'mulet'
 [test_paste_selection.html]
 skip-if = buildapp == 'mulet'
 [test_picture_mutations.html]
 [test_picture_pref.html]
 [test_resource_timing.html]
--- a/dom/tests/mochitest/notification/mochitest.ini
+++ b/dom/tests/mochitest/notification/mochitest.ini
@@ -1,12 +1,12 @@
 [DEFAULT]
 skip-if = e10s || buildapp == 'mulet'
 support-files =
   MockServices.js
   NotificationTest.js
 
 [test_notification_basics.html]
 [test_notification_storage.html]
-skip-if = (toolkit == 'gonk')
+skip-if = toolkit == 'android' || toolkit == 'gonk' #bug 960762
 [test_bug931307.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only timeout
 [test_notification_resend.html]
--- a/dom/tv/TVListeners.h
+++ b/dom/tv/TVListeners.h
@@ -10,17 +10,17 @@
 #include "mozilla/dom/TVSource.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsITVService.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
-class TVSourceListener : public nsITVSourceListener
+class TVSourceListener MOZ_FINAL : public nsITVSourceListener
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(TVSourceListener)
   NS_DECL_NSITVSOURCELISTENER
 
   void RegisterSource(TVSource* aSource);
 
--- a/dom/tv/TVProgram.h
+++ b/dom/tv/TVProgram.h
@@ -66,17 +66,16 @@ private:
   nsCOMPtr<nsISupports> mOwner;
   nsRefPtr<TVChannel> mChannel;
   nsString mEventId;
   nsString mTitle;
   uint64_t mStartTime;
   uint64_t mDuration;
   nsString mDescription;
   nsString mRating;
-  bool mIsInterrupting;
   nsTArray<nsString> mAudioLanguages;
   nsTArray<nsString> mSubtitleLanguages;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_TVProgram_h__
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -52,16 +52,20 @@ support-files =
   sharedWorker_sharedWorker.js
   simpleThread_worker.js
   suspend_iframe.html
   suspend_worker.js
   terminate_worker.js
   terminateSyncXHR_frame.html
   terminateSyncXHR_worker.js
   testXHR.txt
+  test_csp.html^headers^
+  test_csp.js
+  test_xhr_parameters.js
+  test_xhr_system.js
   threadErrors_worker1.js
   threadErrors_worker2.js
   threadErrors_worker3.js
   threadErrors_worker4.js
   threadTimeouts_worker.js
   throwingOnerror_worker.js
   timeoutTracing_worker.js
   transferable_worker.js
@@ -105,18 +109,16 @@ support-files =
 [test_clearTimeouts.html]
 [test_close.html]
 [test_closeOnGC.html]
 [test_console.html]
 [test_consoleReplaceable.html]
 [test_contentWorker.html]
 [test_csp.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
-[test_csp.html^headers^]
-[test_csp.js]
 [test_dataURLWorker.html]
 [test_errorPropagation.html]
 skip-if = buildapp == 'b2g' # b2g(times out) b2g-debug(times out) b2g-desktop(times out)
 [test_errorwarning.html]
 skip-if = buildapp == 'b2g' # b2g(Failed to load script: errorwarning_worker.js) b2g-debug(Failed to load script: errorwarning_worker.js) b2g-desktop(Failed to load script: errorwarning_worker.js)
 [test_eventDispatch.html]
 [test_fibonacci.html]
 skip-if = buildapp == 'b2g' # b2g(Failed to load script: fibonacci_worker.js) b2g-debug(Failed to load script: fibonacci_worker.js) b2g-desktop(Failed to load script: fibonacci_worker.js)
@@ -164,21 +166,19 @@ skip-if = buildapp == 'b2g' || e10s # b2
 [test_worker_performance_now.html]
 [test_xhr.html]
 [test_xhr2.html]
 [test_xhrAbort.html]
 [test_xhr_headers.html]
 [test_xhr_implicit_cancel.html]
 [test_xhr_parameters.html]
 skip-if = buildapp == 'b2g' || e10s
-[test_xhr_parameters.js]
 [test_xhr_responseURL.html]
 [test_xhr_system.html]
 skip-if = buildapp == 'b2g' || e10s
-[test_xhr_system.js]
 [test_xhr_timeout.html]
 skip-if = (os == "win") || (os == "mac") || toolkit == 'android' || e10s #bug 798220
 [test_url_exceptions.html]
 [test_urlSearchParams.html]
 [test_bug1060621.html]
 [test_websocket_basic.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
 [test_websocket.html]
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -13,16 +13,17 @@
 #include "nsReadableUtils.h"
 #include "nsXBLProtoImplMethod.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
 #include "xpcpublic.h"
 #include "nsXBLPrototypeBinding.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsXBLProtoImplMethod::nsXBLProtoImplMethod(const char16_t* aName) :
   nsXBLProtoImplMember(aName),
   mMethod()
@@ -98,26 +99,31 @@ nsXBLProtoImplMethod::SetLineNumber(uint
 nsresult
 nsXBLProtoImplMethod::InstallMember(JSContext* aCx,
                                     JS::Handle<JSObject*> aTargetClassObject)
 {
   NS_PRECONDITION(IsCompiled(),
                   "Should not be installing an uncompiled method");
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
 
-  JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
-  MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
-             xpc::IsInAddonScope(globalObject) ||
-             globalObject == xpc::GetXBLScope(aCx, globalObject));
+#ifdef DEBUG
+  {
+    JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
+    MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
+               xpc::IsInAddonScope(globalObject) ||
+               globalObject == xpc::GetXBLScope(aCx, globalObject));
+    MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
+  }
+#endif
 
   JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
   if (jsMethodObject) {
     nsDependentString name(mName);
 
-    JS::Rooted<JSObject*> method(aCx, JS_CloneFunctionObject(aCx, jsMethodObject, globalObject));
+    JS::Rooted<JSObject*> method(aCx, JS::CloneFunctionObject(aCx, jsMethodObject));
     NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY);
 
     if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
                                static_cast<const char16_t*>(mName),
                                name.Length(), method,
                                JSPROP_ENUMERATE)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
@@ -189,18 +195,17 @@ nsXBLProtoImplMethod::CompileMember(Auto
     functionUri.Truncate(hash);
   }
 
   JSContext *cx = jsapi.cx();
   JSAutoCompartment ac(cx, aClassObject);
   JS::CompileOptions options(cx);
   options.setFileAndLine(functionUri.get(),
                          uncompiledMethod->mBodyText.GetLineNumber())
-         .setVersion(JSVERSION_LATEST)
-         .setDefineOnScope(false);
+         .setVersion(JSVERSION_LATEST);
   JS::Rooted<JSObject*> methodObject(cx);
   JS::AutoObjectVector emptyVector(cx);
   nsresult rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, cname,
                                            paramCount,
                                            const_cast<const char**>(args),
                                            body, methodObject.address());
 
   // Destroy our uncompiled method and delete our arg list.
@@ -264,16 +269,17 @@ nsXBLProtoImplMethod::Write(nsIObjectOut
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAddonId)
 {
+  MOZ_ASSERT(aBoundElement->IsElement());
   NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
 
   if (!GetCompiledMethod()) {
     // Nothing to do here
     return NS_OK;
   }
 
   // Get the script context the same way
@@ -290,47 +296,46 @@ nsXBLProtoImplAnonymousMethod::Execute(n
 
   // We are going to run script via JS::Call, so we need a script entry point,
   // but as this is XBL related it does not appear in the HTML spec.
   dom::AutoEntryScript aes(global);
   JSContext* cx = aes.cx();
 
   JS::Rooted<JSObject*> globalObject(cx, global->GetGlobalJSObject());
 
-  JS::Rooted<JS::Value> v(cx);
-  nsresult rv = nsContentUtils::WrapNative(cx, aBoundElement, &v);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  JS::Rooted<JSObject*> thisObject(cx, &v.toObject());
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, aAddonId));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   JSAutoCompartment ac(cx, scopeObject);
-  if (!JS_WrapObject(cx, &thisObject))
-      return NS_ERROR_OUT_OF_MEMORY;
+  JS::AutoObjectVector scopeChain(cx);
+  if (!nsJSUtils::GetScopeChainForElement(cx, aBoundElement->AsElement(),
+                                          scopeChain)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  MOZ_ASSERT(scopeChain.length() != 0);
 
-  // Clone the function object, using thisObject as the parent so "this" is in
-  // the scope chain of the resulting function (for backwards compat to the
-  // days when this was an event handler).
+  // Clone the function object, using our scope chain (for backwards
+  // compat to the days when this was an event handler).
   JS::Rooted<JSObject*> jsMethodObject(cx, GetCompiledMethod());
-  JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, jsMethodObject, thisObject));
+  JS::Rooted<JSObject*> method(cx, JS::CloneFunctionObject(cx, jsMethodObject,
+                                                           scopeChain));
   if (!method)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Now call the method
 
   // Check whether script is enabled.
   bool scriptAllowed = nsContentUtils::GetSecurityManager()->
                          ScriptAllowed(js::GetGlobalForObjectCrossCompartment(method));
 
   bool ok = true;
   if (scriptAllowed) {
     JS::Rooted<JS::Value> retval(cx);
     JS::Rooted<JS::Value> methodVal(cx, JS::ObjectValue(*method));
-    ok = ::JS::Call(cx, thisObject, methodVal, JS::HandleValueArray::empty(), &retval);
+    ok = ::JS::Call(cx, scopeChain[0], methodVal, JS::HandleValueArray::empty(), &retval);
   }
 
   if (!ok) {
     // If a constructor or destructor threw an exception, it doesn't stop
     // anything else.  We just report it.  Note that we need to set aside the
     // frame chain here, since the constructor invocation is not related to
     // whatever is on the stack right now, really.
     nsJSUtils::ReportPendingException(cx);
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -123,31 +123,37 @@ const char* gPropertyArgs[] = { "val" };
 nsresult
 nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
                                       JS::Handle<JSObject*> aTargetClassObject)
 {
   NS_PRECONDITION(mIsCompiled,
                   "Should not be installing an uncompiled property");
   MOZ_ASSERT(mGetter.IsCompiled() && mSetter.IsCompiled());
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
-  JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
-  MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
-             xpc::IsInAddonScope(globalObject) ||
-             globalObject == xpc::GetXBLScope(aCx, globalObject));
+
+#ifdef DEBUG
+  {
+    JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
+    MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
+               xpc::IsInAddonScope(globalObject) ||
+               globalObject == xpc::GetXBLScope(aCx, globalObject));
+    MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
+  }
+#endif
 
   JS::Rooted<JSObject*> getter(aCx, mGetter.GetJSFunction());
   JS::Rooted<JSObject*> setter(aCx, mSetter.GetJSFunction());
   if (getter || setter) {
     if (getter) {
-      if (!(getter = ::JS_CloneFunctionObject(aCx, getter, globalObject)))
+      if (!(getter = JS::CloneFunctionObject(aCx, getter)))
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (setter) {
-      if (!(setter = ::JS_CloneFunctionObject(aCx, setter, globalObject)))
+      if (!(setter = JS::CloneFunctionObject(aCx, setter)))
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     nsDependentString name(mName);
     if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
                                static_cast<const char16_t*>(mName),
                                name.Length(), JS::UndefinedHandleValue, mJSAttributes,
                                JS_DATA_TO_FUNC_PTR(JSNative, getter.get()),
@@ -187,18 +193,17 @@ nsXBLProtoImplProperty::CompileMember(Au
   bool deletedGetter = false;
   nsXBLTextWithLineNumber *getterText = mGetter.GetUncompiled();
   if (getterText && getterText->GetText()) {
     nsDependentString getter(getterText->GetText());
     if (!getter.IsEmpty()) {
       JSAutoCompartment ac(cx, aClassObject);
       JS::CompileOptions options(cx);
       options.setFileAndLine(functionUri.get(), getterText->GetLineNumber())
-             .setVersion(JSVERSION_LATEST)
-             .setDefineOnScope(false);
+             .setVersion(JSVERSION_LATEST);
       nsCString name = NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName);
       JS::Rooted<JSObject*> getterObject(cx);
       JS::AutoObjectVector emptyVector(cx);
       rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 0,
                                       nullptr, getter, getterObject.address());
 
       delete getterText;
       deletedGetter = true;
@@ -234,18 +239,17 @@ nsXBLProtoImplProperty::CompileMember(Au
   bool deletedSetter = false;
   nsXBLTextWithLineNumber *setterText = mSetter.GetUncompiled();
   if (setterText && setterText->GetText()) {
     nsDependentString setter(setterText->GetText());
     if (!setter.IsEmpty()) {
       JSAutoCompartment ac(cx, aClassObject);
       JS::CompileOptions options(cx);
       options.setFileAndLine(functionUri.get(), setterText->GetLineNumber())
-             .setVersion(JSVERSION_LATEST)
-             .setDefineOnScope(false);
+             .setVersion(JSVERSION_LATEST);
       nsCString name = NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName);
       JS::Rooted<JSObject*> setterObject(cx);
       JS::AutoObjectVector emptyVector(cx);
       rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 1,
                                       gPropertyArgs, setter,
                                       setterObject.address());
 
       delete setterText;
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -39,16 +39,17 @@
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsXBLEventHandler.h"
 #include "nsXBLSerialize.h"
 #include "nsJSUtils.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/JSEventHandler.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/dom/EventHandlerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "xpcpublic.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 uint32_t nsXBLPrototypeHandler::gRefCnt = 0;
@@ -295,26 +296,25 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
   // First, enter our XBL scope. This is where the generic handler should have
   // been compiled, above.
   JSAutoCompartment ac(cx, scopeObject);
   JS::Rooted<JSObject*> genericHandler(cx, handler.get());
   bool ok = JS_WrapObject(cx, &genericHandler);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   MOZ_ASSERT(!js::IsCrossCompartmentWrapper(genericHandler));
 
-  // Wrap the native into the XBL scope. This creates a reflector in the document
-  // scope if one doesn't already exist, and potentially wraps it cross-
-  // compartment into our scope (via aAllowWrapping=true).
-  JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
-  rv = nsContentUtils::WrapNative(cx, scriptTarget, &targetV);
-  NS_ENSURE_SUCCESS(rv, rv);
+  // Build a scope chain in the XBL scope.
+  nsRefPtr<Element> targetElement = do_QueryObject(scriptTarget);
+  JS::AutoObjectVector scopeChain(cx);
+  ok = nsJSUtils::GetScopeChainForElement(cx, targetElement, scopeChain);
+  NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 
-  // Next, clone the generic handler to be parented to the target.
-  JS::Rooted<JSObject*> target(cx, &targetV.toObject());
-  JS::Rooted<JSObject*> bound(cx, JS_CloneFunctionObject(cx, genericHandler, target));
+  // Next, clone the generic handler with our desired scope chain.
+  JS::Rooted<JSObject*> bound(cx, JS::CloneFunctionObject(cx, genericHandler,
+                                                          scopeChain));
   NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
 
   nsRefPtr<EventHandlerNonNull> handlerCallback =
     new EventHandlerNonNull(bound, /* aIncumbentGlobal = */ nullptr);
 
   TypedEventHandler typedHandler(handlerCallback);
 
   // Execute it.
@@ -365,18 +365,17 @@ nsXBLPrototypeHandler::EnsureEventHandle
   const char **argNames;
   nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, false, &argCount,
                                    &argNames);
 
   // Compile the event handler in the xbl scope.
   JSAutoCompartment ac(cx, scopeObject);
   JS::CompileOptions options(cx);
   options.setFileAndLine(bindingURI.get(), mLineNumber)
-         .setVersion(JSVERSION_LATEST)
-         .setDefineOnScope(false);
+         .setVersion(JSVERSION_LATEST);
 
   JS::Rooted<JSObject*> handlerFun(cx);
   JS::AutoObjectVector emptyVector(cx);
   nsresult rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options,
                                            nsAtomCString(aName), argCount,
                                            argNames, handlerText,
                                            handlerFun.address());
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -601,24 +601,21 @@ public:
       GetElementsByAttributeNS(const nsAString& aNamespaceURI,
                                const nsAString& aAttribute,
                                const nsAString& aValue,
                                mozilla::ErrorResult& rv);
     // Style() inherited from nsStyledElement
     already_AddRefed<nsFrameLoader> GetFrameLoader();
     void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& rv);
 
-    // For XUL, the parent is the parent element, if any
-    mozilla::dom::ParentObject GetParentObject() const
+    nsINode* GetScopeChainParent() const MOZ_OVERRIDE
     {
+        // For XUL, the parent is the parent element, if any
         Element* parent = GetParentElement();
-        if (parent) {
-          return GetParentObjectInternal(parent);
-        }
-        return nsStyledElement::GetParentObject();
+        return parent ? parent : nsStyledElement::GetScopeChainParent();
     }
 
 protected:
     ~nsXULElement();
 
     // This can be removed if EnsureContentsGenerated dies.
     friend class nsNSElementTearoff;
 
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -38,16 +38,29 @@ MOZ_BEGIN_ENUM_CLASS(SurfaceFormat, int8
   R8G8B8A8,
   R8G8B8X8,
   R5G6B5,
   A8,
   YUV,
   UNKNOWN
 MOZ_END_ENUM_CLASS(SurfaceFormat)
 
+inline bool IsOpaque(SurfaceFormat aFormat)
+{
+  switch (aFormat) {
+  case SurfaceFormat::B8G8R8X8:
+  case SurfaceFormat::R8G8B8X8:
+  case SurfaceFormat::R5G6B5:
+  case SurfaceFormat::YUV:
+    return true;
+  default:
+    return false;
+  }
+}
+
 MOZ_BEGIN_ENUM_CLASS(FilterType, int8_t)
   BLEND = 0,
   TRANSFORM,
   MORPHOLOGY,
   COLOR_MATRIX,
   FLOOD,
   TILE,
   TABLE_TRANSFER,
--- a/gfx/gl/GLConsts.h
+++ b/gfx/gl/GLConsts.h
@@ -5182,16 +5182,17 @@
 #define LOCAL_EGL_CONTEXT_PRIORITY_MEDIUM_IMG                0x3102
 #define LOCAL_EGL_CORE_NATIVE_ENGINE                         0x305B
 #define LOCAL_EGL_COVERAGE_BUFFERS_NV                        0x30E0
 #define LOCAL_EGL_COVERAGE_SAMPLES_NV                        0x30E1
 #define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV         0x3132
 #define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV            0x3133
 #define LOCAL_EGL_COVERAGE_SAMPLE_RESOLVE_NV                 0x3131
 #define LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE          0x3200
+#define LOCAL_EGL_DXGI_KEYED_MUTEX_ANGLE                     0x3209
 #define LOCAL_EGL_DEFAULT_DISPLAY                            ((EGLNativeDisplayType)0)
 #define LOCAL_EGL_DEPTH_ENCODING_NONE_NV                     0
 #define LOCAL_EGL_DEPTH_ENCODING_NONLINEAR_NV                0x30E3
 #define LOCAL_EGL_DEPTH_ENCODING_NV                          0x30E2
 #define LOCAL_EGL_DEPTH_SIZE                                 0x3025
 #define LOCAL_EGL_DISCARD_SAMPLES_ARM                        0x3286
 #define LOCAL_EGL_DISPLAY_SCALING                            10000
 #define LOCAL_EGL_DMA_BUF_PLANE0_FD_EXT                      0x3272
--- a/gfx/gl/SharedSurfaceANGLE.cpp
+++ b/gfx/gl/SharedSurfaceANGLE.cpp
@@ -1,18 +1,20 @@
 /* -*- 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 "SharedSurfaceANGLE.h"
-
 #include "GLContextEGL.h"
 #include "GLLibraryEGL.h"
 
+#include <d3d11.h>
+#include "gfxWindowsPlatform.h"
+
 namespace mozilla {
 namespace gl {
 
 // Returns `EGL_NO_SURFACE` (`0`) on error.
 static EGLSurface
 CreatePBufferSurface(GLLibraryEGL* egl,
                      EGLDisplay display,
                      EGLConfig config,
@@ -60,52 +62,60 @@ SharedSurface_ANGLEShareHandle::Create(G
     bool ok = egl->fQuerySurfacePointerANGLE(display,
                                              pbuffer,
                                              LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
                                              &shareHandle);
     if (!ok) {
         egl->fDestroySurface(egl->Display(), pbuffer);
         return nullptr;
     }
+    void* opaqueKeyedMutex = nullptr;
+    egl->fQuerySurfacePointerANGLE(display,
+                                   pbuffer,
+                                   LOCAL_EGL_DXGI_KEYED_MUTEX_ANGLE,
+                                   &opaqueKeyedMutex);
+    RefPtr<IDXGIKeyedMutex> keyedMutex = static_cast<IDXGIKeyedMutex*>(opaqueKeyedMutex);
 
     GLuint fence = 0;
     if (gl->IsExtensionSupported(GLContext::NV_fence)) {
         gl->MakeCurrent();
         gl->fGenFences(1, &fence);
     }
 
     typedef SharedSurface_ANGLEShareHandle ptrT;
     UniquePtr<ptrT> ret( new ptrT(gl, egl, size, hasAlpha, context,
-                                  pbuffer, shareHandle, fence) );
+                                  pbuffer, shareHandle, keyedMutex, fence) );
     return Move(ret);
 }
 
 EGLDisplay
 SharedSurface_ANGLEShareHandle::Display()
 {
     return mEGL->Display();
 }
 
 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl,
                                                                GLLibraryEGL* egl,
                                                                const gfx::IntSize& size,
                                                                bool hasAlpha,
                                                                EGLContext context,
                                                                EGLSurface pbuffer,
                                                                HANDLE shareHandle,
+                                                               const RefPtr<IDXGIKeyedMutex>& keyedMutex,
                                                                GLuint fence)
     : SharedSurface(SharedSurfaceType::EGLSurfaceANGLE,
                     AttachmentType::Screen,
                     gl,
                     size,
                     hasAlpha)
     , mEGL(egl)
     , mContext(context)
     , mPBuffer(pbuffer)
     , mShareHandle(shareHandle)
+    , mKeyedMutex(keyedMutex)
     , mFence(fence)
 {
 }
 
 
 SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle()
 {
     mEGL->fDestroySurface(Display(), mPBuffer);
@@ -141,16 +151,68 @@ SharedSurface_ANGLEShareHandle::WaitSync
 
 bool
 SharedSurface_ANGLEShareHandle::PollSync()
 {
     return true;
 }
 
 void
+SharedSurface_ANGLEShareHandle::ProducerAcquireImpl()
+{
+  if (mKeyedMutex)
+      mKeyedMutex->AcquireSync(0, INFINITE);
+}
+
+void
+SharedSurface_ANGLEShareHandle::ProducerReleaseImpl()
+{
+    if (mKeyedMutex) {
+        // XXX: ReleaseSync() has an implicit flush of the D3D commands
+        // whether we need Flush() or not depends on the ANGLE semantics.
+        // For now, we'll just do it
+        mGL->fFlush();
+        mKeyedMutex->ReleaseSync(0);
+        return;
+    }
+    Fence();
+}
+
+void
+SharedSurface_ANGLEShareHandle::ConsumerAcquireImpl()
+{
+    if (!mConsumerTexture) {
+        RefPtr<ID3D11Texture2D> tex;
+        HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetD3D11Device()->OpenSharedResource(mShareHandle,
+                                                                                             __uuidof(ID3D11Texture2D),
+                                                                                             (void**)(ID3D11Texture2D**)byRef(tex));
+        if (SUCCEEDED(hr)) {
+            mConsumerTexture = tex;
+            RefPtr<IDXGIKeyedMutex> mutex;
+            hr = tex->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
+
+            if (SUCCEEDED(hr)) {
+                mConsumerKeyedMutex = mutex;
+            }
+        }
+    }
+
+    if (mConsumerKeyedMutex)
+        mConsumerKeyedMutex->AcquireSync(0, INFINITE);
+}
+
+void
+SharedSurface_ANGLEShareHandle::ConsumerReleaseImpl()
+{
+    if (mConsumerKeyedMutex) {
+        mConsumerKeyedMutex->ReleaseSync(0);
+    }
+}
+
+void
 SharedSurface_ANGLEShareHandle::Fence_ContentThread_Impl()
 {
     if (mFence) {
         MOZ_ASSERT(mGL->IsExtensionSupported(GLContext::NV_fence));
         mGL->fSetFence(mFence, LOCAL_GL_ALL_COMPLETED_NV);
         mGL->fFlush();
         return;
     }
--- a/gfx/gl/SharedSurfaceANGLE.h
+++ b/gfx/gl/SharedSurfaceANGLE.h
@@ -2,18 +2,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/. */
 
 #ifndef SHARED_SURFACE_ANGLE_H_
 #define SHARED_SURFACE_ANGLE_H_
 
 #include <windows.h>
+#include "SharedSurface.h"
 
-#include "SharedSurface.h"
+struct IDXGIKeyedMutex;
+struct ID3D11Texture2D;
 
 namespace mozilla {
 namespace gl {
 
 class GLContext;
 class GLLibraryEGL;
 
 class SharedSurface_ANGLEShareHandle
@@ -32,47 +34,60 @@ public:
         return (SharedSurface_ANGLEShareHandle*)surf;
     }
 
 protected:
     GLLibraryEGL* const mEGL;
     const EGLContext mContext;
     const EGLSurface mPBuffer;
     const HANDLE mShareHandle;
+    RefPtr<IDXGIKeyedMutex> mKeyedMutex;
+    RefPtr<IDXGIKeyedMutex> mConsumerKeyedMutex;
+    RefPtr<ID3D11Texture2D> mConsumerTexture;
+
     const GLuint mFence;
 
     SharedSurface_ANGLEShareHandle(GLContext* gl,
                                    GLLibraryEGL* egl,
                                    const gfx::IntSize& size,
                                    bool hasAlpha,
                                    EGLContext context,
                                    EGLSurface pbuffer,
                                    HANDLE shareHandle,
+                                   const RefPtr<IDXGIKeyedMutex>& keyedMutex,
                                    GLuint fence);
 
     EGLDisplay Display();
 
 public:
     virtual ~SharedSurface_ANGLEShareHandle();
 
     virtual void LockProdImpl() MOZ_OVERRIDE;
     virtual void UnlockProdImpl() MOZ_OVERRIDE;
 
     virtual void Fence() MOZ_OVERRIDE;
+    virtual void ProducerAcquireImpl() MOZ_OVERRIDE;
+    virtual void ProducerReleaseImpl() MOZ_OVERRIDE;
+    virtual void ConsumerAcquireImpl() MOZ_OVERRIDE;
+    virtual void ConsumerReleaseImpl() 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;
 
     // Implementation-specific functions below:
     HANDLE GetShareHandle() {
         return mShareHandle;
     }
+
+    const RefPtr<ID3D11Texture2D>& GetConsumerTexture() const {
+        return mConsumerTexture;
+    }
 };
 
 
 
 class SurfaceFactory_ANGLEShareHandle
     : public SurfaceFactory
 {
 protected:
--- a/gfx/layers/GrallocImages.cpp
+++ b/gfx/layers/GrallocImages.cpp
@@ -71,16 +71,18 @@ GrallocImage::SetData(const Data& aData)
     // Emulator does not support HAL_PIXEL_FORMAT_YV12.
     return;
   }
 
   RefPtr<GrallocTextureClientOGL> textureClient =
        new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
                                    gfx::SurfaceFormat::UNKNOWN,
                                    gfx::BackendType::NONE);
+  // GrallocImages are all YUV and don't support alpha.
+  textureClient->SetIsOpaque(true);
   bool result =
     textureClient->AllocateGralloc(mData.mYSize,
                                    HAL_PIXEL_FORMAT_YV12,
                                    GraphicBuffer::USAGE_SW_READ_OFTEN |
                                    GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                                    GraphicBuffer::USAGE_HW_TEXTURE);
   sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
   if (!result || !graphicBuffer.get()) {
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -77,17 +77,21 @@ MOZ_END_ENUM_CLASS(SurfaceMode)
 // LayerRenderState for Composer2D
 // We currently only support Composer2D using gralloc. If we want to be backed
 // by other surfaces we will need a more generic LayerRenderState.
 MOZ_BEGIN_ENUM_CLASS(LayerRenderStateFlags, int8_t)
   LAYER_RENDER_STATE_DEFAULT = 0,
   Y_FLIPPED = 1 << 0,
   BUFFER_ROTATION = 1 << 1,
   // Notify Composer2D to swap the RB pixels of gralloc buffer
-  FORMAT_RB_SWAP = 1 << 2
+  FORMAT_RB_SWAP = 1 << 2,
+  // We record opaqueness here alongside the actual surface we're going to
+  // render. This avoids confusion when a layer might return different kinds
+  // of surfaces over time (e.g. video frames).
+  OPAQUE = 1 << 3
 MOZ_END_ENUM_CLASS(LayerRenderStateFlags)
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(LayerRenderStateFlags)
 
 // The 'ifdef MOZ_WIDGET_GONK' sadness here is because we don't want to include
 // android::sp unless we have to.
 struct LayerRenderState {
   LayerRenderState()
 #ifdef MOZ_WIDGET_GONK
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -281,46 +281,41 @@ typedef mozilla::gfx::Matrix4x4 Matrix4x
  *
  * "apz.num_paint_duration_samples"
  * Number of samples to store of how long it took to paint after the previous
  *
  * "apz.overscroll.enabled"
  * Pref that enables overscrolling. If this is disabled, excess scroll that
  * cannot be handed off is discarded.
  *
- * "apz.overscroll.fling_friction"
- * Amount of friction applied during flings when in overscroll.
- *
- * "apz.overscroll.fling_stopped_threshold"
- * When flinging in an overscrolled state, if the velocity goes below this
- * number, we stop the fling.
- * Units: screen pixels per millisecond
- *
  * "apz.overscroll.min_pan_distance_ratio"
  * The minimum ratio of the pan distance along one axis to the pan distance
  * along the other axis needed to initiate overscroll along the first axis
  * during panning.
  *
  * "apz.overscroll.stretch_factor"
  * How much overscrolling can stretch content along an axis.
  * The maximum stretch along an axis is a factor of (1 + kStretchFactor).
  * (So if kStretchFactor is 0, you can't stretch at all; if kStretchFactor
  * is 1, you can stretch at most by a factor of 2).
  *
- * "apz.overscroll.snap_back.spring_stiffness"
+ * "apz.overscroll.spring_stiffness"
  * The stiffness of the spring used in the physics model for the overscroll
- * snap-back animation.
+ * animation.
  *
- * "apz.overscroll.snap_back.spring_damping"
+ * "apz.overscroll.spring_friction"
  * The friction of the spring used in the physics model for the overscroll
- * snap-back animation.
+ * animation.
  *
- * "apz.overscroll.snap_back.mass"
- * The mass of the page in the physics model for the overscroll snap-back
- * animation.
+ * "apz.overscroll.stop_distance_threshold"
+ * "apz.overscroll.stop_velocity_threshold"
+ * Thresholds for stopping the overscroll animation. When both the distance
+ * and the velocity fall below their thresholds, we stop oscillating.
+ * Units: screen pixels (for distance)
+ *        screen pixels per millisecond (for velocity)
  *
  * "apz.pan_repaint_interval"
  * Maximum amount of time while panning before sending a viewport change. This
  * will asynchronously repaint the page. It is also forced when panning stops.
  *
  * "apz.smooth_scroll_repaint_interval"
  * Maximum amount of time doing a smooth scroll before sending a viewport
  * change. This will asynchronously repaint the page.
@@ -467,25 +462,37 @@ private:
   AsyncPanZoomController* mApzc;
   AsyncPanZoomController::PanZoomState mInitialState;
 };
 
 class FlingAnimation: public AsyncPanZoomAnimation {
 public:
   FlingAnimation(AsyncPanZoomController& aApzc,
                  const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
-                 bool aApplyAcceleration,
-                 bool aAllowOverscroll)
+                 bool aApplyAcceleration)
     : AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
     , mApzc(aApzc)
     , mOverscrollHandoffChain(aOverscrollHandoffChain)
-    , mAllowOverscroll(aAllowOverscroll)
   {
     MOZ_ASSERT(mOverscrollHandoffChain);
     TimeStamp now = GetFrameTime();
+
+    // Drop any velocity on axes where we don't have room to scroll anyways.
+    // This ensures that we don't take the 'overscroll' path in Sample()
+    // on account of one axis which can't scroll having a velocity.
+    {
+      ReentrantMonitorAutoEnter lock(mApzc.mMonitor);
+      if (!mApzc.mX.CanScroll()) {
+        mApzc.mX.SetVelocity(0);
+      }
+      if (!mApzc.mY.CanScroll()) {
+        mApzc.mY.SetVelocity(0);
+      }
+    }
+
     ScreenPoint velocity(mApzc.mX.GetVelocity(), mApzc.mY.GetVelocity());
 
     // If the last fling was very recent and in the same direction as this one,
     // boost the velocity to be the sum of the two. Check separate axes separately
     // because we could have two vertical flings with small horizontal components
     // on the opposite side of zero, and we still want the y-fling to get accelerated.
     // Note that the acceleration code is only applied on the APZC that initiates
     // the fling; the accelerated velocities are then handed off using the
@@ -526,21 +533,18 @@ public:
     // SampleContentTransformForFrame() with the same sample time. If we allow
     // the negative aDelta to be processed, it will yield a displacement in the
     // direction opposite to the fling, which can cause us to overscroll and
     // hand off the fling to _our_ parent, which effectively kills the fling.
     if (aDelta.ToMilliseconds() <= 0) {
       return true;
     }
 
-    bool overscrolled = mApzc.IsOverscrolled();
-    float friction = overscrolled ? gfxPrefs::APZOverscrollFlingFriction()
-                                  : gfxPrefs::APZFlingFriction();
-    float threshold = overscrolled ? gfxPrefs::APZOverscrollFlingStoppedThreshold()
-                                   : gfxPrefs::APZFlingStoppedThreshold();
+    float friction = gfxPrefs::APZFlingFriction();
+    float threshold = gfxPrefs::APZFlingStoppedThreshold();
 
     bool shouldContinueFlingX = mApzc.mX.FlingApplyFrictionOrCancel(aDelta, friction, threshold),
          shouldContinueFlingY = mApzc.mY.FlingApplyFrictionOrCancel(aDelta, friction, threshold);
     // If we shouldn't continue the fling, let's just stop and repaint.
     if (!shouldContinueFlingX && !shouldContinueFlingY) {
       APZC_LOG("%p ending fling animation. overscrolled=%d\n", &mApzc, mApzc.IsOverscrolled());
       // This APZC or an APZC further down the handoff chain may be be overscrolled.
       // Start a snap-back animation on the overscrolled APZC.
@@ -571,58 +575,47 @@ public:
     ScreenPoint adjustedOffset;
     mApzc.mX.AdjustDisplacement(offset.x, adjustedOffset.x, overscroll.x);
     mApzc.mY.AdjustDisplacement(offset.y, adjustedOffset.y, overscroll.y);
 
     aFrameMetrics.ScrollBy(adjustedOffset / aFrameMetrics.GetZoom());
 
     // The fling may have caused us to reach the end of our scroll range.
     if (!IsZero(overscroll)) {
-      if (mAllowOverscroll) {
-        // If this is a fling that allows overscroll, then go into overscroll.
-
-        mApzc.OverscrollBy(overscroll);
-
-        // Restore the velocity of the fling, which was zeroed out by
-        // AdjustDisplacement().
-        mApzc.mX.SetVelocity(velocity.x);
-        mApzc.mY.SetVelocity(velocity.y);
-
-      } else {
-        // Otherwise, hand off the fling to the next APZC in the overscroll
-        // handoff chain.
-
-        // We may have reached the end of the scroll range along one axis but
-        // not the other. In such a case we only want to hand off the relevant
-        // component of the fling.
-        if (FuzzyEqualsAdditive(overscroll.x, 0.0f, COORDINATE_EPSILON)) {
-          velocity.x = 0;
-        } else if (FuzzyEqualsAdditive(overscroll.y, 0.0f, COORDINATE_EPSILON)) {
-          velocity.y = 0;
-        }
-
-        // To hand off the fling, we attempt to find a target APZC and start a new
-        // fling with the same velocity on that APZC. For simplicity, the actual
-        // overscroll of the current sample is discarded rather than being handed
-        // off. The compositor should sample animations sufficiently frequently
-        // that this is not noticeable. The target APZC is chosen by seeing if
-        // there is an APZC further in the handoff chain which is pannable; if
-        // there isn't, we take the new fling ourselves, entering an overscrolled
-        // state.
-        // Note: APZC is holding mMonitor, so directly calling
-        // HandleFlingOverscroll() (which acquires the tree lock) would violate
-        // the lock ordering. Instead we schedule HandleFlingOverscroll() to be
-        // called after mMonitor is released.
-        mDeferredTasks.append(NewRunnableMethod(&mApzc,
-                                                &AsyncPanZoomController::HandleFlingOverscroll,
-                                                velocity,
-                                                mOverscrollHandoffChain));
-
-        return false;
+      // Hand off the fling to the next APZC in the overscroll handoff chain.
+
+      // We may have reached the end of the scroll range along one axis but
+      // not the other. In such a case we only want to hand off the relevant
+      // component of the fling.
+      // TODO(botond): If our intention is to continue the other component
+      // in this APZC, we should not be returning 'false'.
+      if (FuzzyEqualsAdditive(overscroll.x, 0.0f, COORDINATE_EPSILON)) {
+        velocity.x = 0;
+      } else if (FuzzyEqualsAdditive(overscroll.y, 0.0f, COORDINATE_EPSILON)) {
+        velocity.y = 0;
       }
+
+      // To hand off the fling, we attempt to find a target APZC and start a new
+      // fling with the same velocity on that APZC. For simplicity, the actual
+      // overscroll of the current sample is discarded rather than being handed
+      // off. The compositor should sample animations sufficiently frequently
+      // that this is not noticeable. The target APZC is chosen by seeing if
+      // there is an APZC further in the handoff chain which is pannable; if
+      // there isn't, we take the new fling ourselves, entering an overscrolled
+      // state.
+      // Note: APZC is holding mMonitor, so directly calling
+      // HandleFlingOverscroll() (which acquires the tree lock) would violate
+      // the lock ordering. Instead we schedule HandleFlingOverscroll() to be
+      // called after mMonitor is released.
+      mDeferredTasks.append(NewRunnableMethod(&mApzc,
+                                              &AsyncPanZoomController::HandleFlingOverscroll,
+                                              velocity,
+                                              mOverscrollHandoffChain));
+
+      return false;
     }
 
     return true;
   }
 
 private:
   static bool SameDirection(float aVelocity1, float aVelocity2)
   {
@@ -634,17 +627,16 @@ private:
   static float Accelerate(float aBase, float aSupplemental)
   {
     return (aBase * gfxPrefs::APZFlingAccelBaseMultiplier())
          + (aSupplemental * gfxPrefs::APZFlingAccelSupplementalMultiplier());
   }
 
   AsyncPanZoomController& mApzc;
   nsRefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
-  bool mAllowOverscroll;
 };
 
 class ZoomAnimation: public AsyncPanZoomAnimation {
 public:
   ZoomAnimation(CSSPoint aStartOffset, CSSToScreenScale aStartZoom,
                 CSSPoint aEndOffset, CSSToScreenScale aEndZoom)
     : mTotalDuration(TimeDuration::FromMilliseconds(gfxPrefs::APZZoomAnimationDuration()))
     , mStartOffset(aStartOffset)
@@ -696,34 +688,31 @@ private:
 
   // Target metrics for a zoom to animation. This is only valid when we are in
   // the "ANIMATED_ZOOM" state. We only use the |mViewportScrollOffset| and
   // |mResolution| fields on this.
   CSSPoint mEndOffset;
   CSSToScreenScale mEndZoom;
 };
 
-class OverscrollSnapBackAnimation: public AsyncPanZoomAnimation {
+class OverscrollAnimation: public AsyncPanZoomAnimation {
 public:
-  explicit OverscrollSnapBackAnimation(AsyncPanZoomController& aApzc)
+  explicit OverscrollAnimation(AsyncPanZoomController& aApzc, const ScreenPoint& aVelocity)
     : mApzc(aApzc)
   {
-    // Make sure the initial velocity is zero. This is normally the case
-    // since we've just stopped a fling, but in some corner cases involving
-    // handoff it could not be.
-    mApzc.mX.SetVelocity(0);
-    mApzc.mY.SetVelocity(0);
+    mApzc.mX.SetVelocity(aVelocity.x);
+    mApzc.mY.SetVelocity(aVelocity.y);
   }
 
   virtual bool Sample(FrameMetrics& aFrameMetrics,
                       const TimeDuration& aDelta) MOZ_OVERRIDE
   {
     // Can't inline these variables due to short-circuit evaluation.
-    bool continueX = mApzc.mX.SampleSnapBack(aDelta);
-    bool continueY = mApzc.mY.SampleSnapBack(aDelta);
+    bool continueX = mApzc.mX.SampleOverscrollAnimation(aDelta);
+    bool continueY = mApzc.mY.SampleOverscrollAnimation(aDelta);
     return continueX || continueY;
   }
 private:
   AsyncPanZoomController& mApzc;
 };
 
 class SmoothScrollAnimation : public AsyncPanZoomAnimation {
 public:
@@ -1212,19 +1201,20 @@ nsEventStatus AsyncPanZoomController::On
       TrackTouch(aEvent);
       return nsEventStatus_eConsumeNoDefault;
 
     case PINCHING:
       // The scale gesture listener should have handled this.
       NS_WARNING("Gesture listener should have handled pinching in OnTouchMove.");
       return nsEventStatus_eIgnore;
 
-    case SNAP_BACK:  // Should not receive a touch-move in the SNAP_BACK state
-                     // as touch blocks that begin in an overscrolled state
-                     // are ignored.
+    case OVERSCROLL_ANIMATION:
+      // Should not receive a touch-move in the OVERSCROLL_ANIMATION state
+      // as touch blocks that begin in an overscrolled state
+      // are ignored.
       NS_WARNING("Received impossible touch in OnTouchMove");
       break;
   }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent) {
@@ -1296,19 +1286,20 @@ nsEventStatus AsyncPanZoomController::On
     return nsEventStatus_eConsumeNoDefault;
   }
   case PINCHING:
     SetState(NOTHING);
     // Scale gesture listener should have handled this.
     NS_WARNING("Gesture listener should have handled pinching in OnTouchEnd.");
     return nsEventStatus_eIgnore;
 
-  case SNAP_BACK:  // Should not receive a touch-move in the SNAP_BACK state
-                   // as touch blocks that begin in an overscrolled state
-                   // are ignored.
+  case OVERSCROLL_ANIMATION:
+    // Should not receive a touch-move in the OVERSCROLL_ANIMATION state
+    // as touch blocks that begin in an overscrolled state
+    // are ignored.
     NS_WARNING("Received impossible touch in OnTouchEnd");
     break;
   }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEvent) {
@@ -1983,57 +1974,52 @@ nsRefPtr<const OverscrollHandoffChain> A
   // scenario, just build a 1-element chain containing ourselves.
   OverscrollHandoffChain* result = new OverscrollHandoffChain;
   result->Add(this);
   return result;
 }
 
 void AsyncPanZoomController::AcceptFling(const ScreenPoint& aVelocity,
                                          const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
-                                         bool aHandoff,
-                                         bool aAllowOverscroll) {
+                                         bool aHandoff) {
   // We may have a pre-existing velocity for whatever reason (for example,
   // a previously handed off fling). We don't want to clobber that.
   mX.SetVelocity(mX.GetVelocity() + aVelocity.x);
   mY.SetVelocity(mY.GetVelocity() + aVelocity.y);
   SetState(FLING);
   StartAnimation(new FlingAnimation(*this,
       aOverscrollHandoffChain,
-      !aHandoff,  // only apply acceleration if this is an initial fling
-      aAllowOverscroll));
+      !aHandoff));  // only apply acceleration if this is an initial fling
 }
 
 bool AsyncPanZoomController::AttemptFling(ScreenPoint aVelocity,
                                           const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
                                           bool aHandoff) {
   // If we are pannable, take over the fling ourselves.
   if (IsPannable()) {
     AcceptFling(aVelocity,
                 aOverscrollHandoffChain,
-                aHandoff,
-                false /* do not allow overscroll */);
+                aHandoff);
     return true;
   }
 
   return false;
 }
 
 void AsyncPanZoomController::HandleFlingOverscroll(const ScreenPoint& aVelocity,
                                                    const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain) {
   APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
   if (!(treeManagerLocal && treeManagerLocal->DispatchFling(this,
                                                             aVelocity,
                                                             aOverscrollHandoffChain,
                                                             true /* handoff */))) {
-    // No one wanted the fling, so we enter into an overscroll fling ourselves.
+    // No one wanted the fling, so we "take it" ourselves by entering an
+    // overscroll animation starting with the fling's velocity.
     if (IsPannable()) {
-      AcceptFling(aVelocity,
-                  aOverscrollHandoffChain,
-                  true /* handoff */,
-                  true /* allow overscroll */);
+      StartOverscrollAnimation(aVelocity);
     }
   }
 }
 
 void AsyncPanZoomController::HandleSmoothScrollOverscroll(const ScreenPoint& aVelocity) {
   // We must call BuildOverscrollHandoffChain from this deferred callback
   // function in order to avoid a deadlock when acquiring the tree lock.
   HandleFlingOverscroll(aVelocity, BuildOverscrollHandoffChain());
@@ -2050,19 +2036,19 @@ void AsyncPanZoomController::StartSmooth
 
   StartAnimation(new SmoothScrollAnimation(*this,
                                            initialPosition, initialVelocity,
                                            destination,
                                            gfxPrefs::ScrollBehaviorSpringConstant(),
                                            gfxPrefs::ScrollBehaviorDampingRatio()));
 }
 
-void AsyncPanZoomController::StartSnapBack() {
-  SetState(SNAP_BACK);
-  StartAnimation(new OverscrollSnapBackAnimation(*this));
+void AsyncPanZoomController::StartOverscrollAnimation(const ScreenPoint& aVelocity) {
+  SetState(OVERSCROLL_ANIMATION);
+  StartAnimation(new OverscrollAnimation(*this, aVelocity));
 }
 
 bool AsyncPanZoomController::CallDispatchScroll(const ScreenPoint& aStartPoint,
                                                 const ScreenPoint& aEndPoint,
                                                 OverscrollHandoffState& aOverscrollHandoffState) {
   // Make a local copy of the tree manager pointer and check if it's not
   // null before calling DispatchScroll(). This is necessary because
   // Destroy(), which nulls out mTreeManager, could be called concurrently.
@@ -2286,17 +2272,17 @@ void AsyncPanZoomController::FlushRepain
   RequestContentRepaint(mFrameMetrics, false /* not throttled */);
   UpdateSharedCompositorFrameMetrics();
 }
 
 bool AsyncPanZoomController::SnapBackIfOverscrolled() {
   ReentrantMonitorAutoEnter lock(mMonitor);
   if (IsOverscrolled()) {
     APZC_LOG("%p is overscrolled, starting snap-back\n", this);
-    StartSnapBack();
+    StartOverscrollAnimation(ScreenPoint(0, 0));
     return true;
   }
   return false;
 }
 
 bool AsyncPanZoomController::IsMovingFast() const {
   ReentrantMonitorAutoEnter lock(mMonitor);
   return (GetVelocityVector().Length() > gfxPrefs::APZFlingStopOnTapThreshold());
@@ -2445,30 +2431,41 @@ Matrix4x4 AsyncPanZoomController::GetOve
   const float kStretchFactor = gfxPrefs::APZOverscrollStretchFactor();
 
   // Compute the amount of the stretch along each axis. The stretch is
   // proportional to the amount by which we are overscrolled along that axis.
   ScreenSize compositionSize(mX.GetCompositionLength(), mY.GetCompositionLength());
   float scaleX = 1 + kStretchFactor * fabsf(mX.GetOverscroll()) / mX.GetCompositionLength();
   float scaleY = 1 + kStretchFactor * fabsf(mY.GetOverscroll()) / mY.GetCompositionLength();
 
+  // If an axis is in underscroll, the interpretation of its overscroll
+  // amount changes: instead of stretching along that axis, we compress.
+  if (mX.IsInUnderscroll()) {
+    scaleX = 1 / scaleX;
+  }
+  if (mY.IsInUnderscroll()) {
+    scaleY = 1 / scaleY;
+  }
+
   // The scale is applied relative to the origin of the composition bounds, i.e.
   // it keeps the top-left corner of the content in place. This is fine if we
   // are overscrolling at the top or on the left, but if we are overscrolling
   // at the bottom or on the right, we want the bottom or right edge of the
   // content to stay in place instead, so we add a translation to compensate.
   ScreenPoint translation;
-  if (mX.IsOverscrolled() && mX.GetOverscroll() > 0) {
-    // Overscrolled on the right.
+  bool overscrolledOnRight = (mX.GetOverscroll() > 0 && !mX.IsInUnderscroll())
+                          || (mX.GetOverscroll() < 0 && mX.IsInUnderscroll());
+  if (overscrolledOnRight) {
     ScreenCoord overscrolledCompositionWidth = scaleX * compositionSize.width;
     ScreenCoord extraCompositionWidth = overscrolledCompositionWidth - compositionSize.width;
     translation.x = -extraCompositionWidth;
   }
-  if (mY.IsOverscrolled() && mY.GetOverscroll() > 0) {
-    // Overscrolled at the bottomn.
+  bool overscrolledAtBottom = (mY.GetOverscroll() > 0 && !mY.IsInUnderscroll())
+                           || (mY.GetOverscroll() < 0 && mY.IsInUnderscroll());
+  if (overscrolledAtBottom) {
     ScreenCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
     ScreenCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;
     translation.y = -extraCompositionHeight;
   }
 
   // Combine the transformations into a matrix.
   return Matrix4x4::Scaling(scaleX, scaleY, 1)
                     .PostTranslate(translation.x, translation.y, 0);
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -720,17 +720,18 @@ protected:
 
     CROSS_SLIDING_X,          /* Panning disabled while user does a horizontal gesture
                                  on a vertically-scrollable view. This used for the
                                  Windows Metro "cross-slide" gesture. */
     CROSS_SLIDING_Y,          /* as above for Y axis */
 
     PINCHING,                 /* nth touch-start, where n > 1. this mode allows pan and zoom */
     ANIMATING_ZOOM,           /* animated zoom to a new rect */
-    SNAP_BACK,                /* snap-back animation to relieve overscroll */
+    OVERSCROLL_ANIMATION,     /* Spring-based animation used to relieve overscroll once
+                                 the finger is lifted. */
     SMOOTH_SCROLL,            /* Smooth scrolling to destination. Used by
                                  CSSOM-View smooth scroll-behavior */
   };
 
   // This is in theory protected by |mMonitor|; that is, it should be held whenever
   // this is updated. In practice though... see bug 897017.
   PanZoomState mState;
 
@@ -824,17 +825,17 @@ public:
    *            fling.
    */
   bool AttemptFling(ScreenPoint aVelocity,
                     const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
                     bool aHandoff);
 
 private:
   friend class FlingAnimation;
-  friend class OverscrollSnapBackAnimation;
+  friend class OverscrollAnimation;
   friend class SmoothScrollAnimation;
   // The initial velocity of the most recent fling.
   ScreenPoint mLastFlingVelocity;
   // The time at which the most recent fling started.
   TimeStamp mLastFlingTime;
 
   // Deal with overscroll resulting from a fling animation. This is only ever
   // called on APZC instances that were actually performing a fling.
@@ -844,21 +845,20 @@ private:
   void HandleFlingOverscroll(const ScreenPoint& aVelocity,
                              const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain);
 
   void HandleSmoothScrollOverscroll(const ScreenPoint& aVelocity);
 
   // Helper function used by TakeOverFling() and HandleFlingOverscroll().
   void AcceptFling(const ScreenPoint& aVelocity,
                    const nsRefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
-                   bool aHandoff,
-                   bool aAllowOverscroll);
+                   bool aHandoff);
 
-  // Start a snap-back animation to relieve overscroll.
-  void StartSnapBack();
+  // Start an overscroll animation with the given initial velocity.
+  void StartOverscrollAnimation(const ScreenPoint& aVelocity);
 
   void StartSmoothScroll();
 
   /* ===================================================================
    * The functions and members in this section are used to build a tree
    * structure out of APZC instances. This tree can only be walked or
    * manipulated while holding the lock in the associated APZCTreeManager
    * instance.
--- a/gfx/layers/apz/src/Axis.cpp
+++ b/gfx/layers/apz/src/Axis.cpp
@@ -32,17 +32,18 @@ namespace layers {
 extern StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction;
 
 Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
   : mPos(0),
     mPosTimeMs(0),
     mVelocity(0.0f),
     mAxisLocked(false),
     mAsyncPanZoomController(aAsyncPanZoomController),
-    mOverscroll(0)
+    mOverscroll(0),
+    mInUnderscroll(false)
 {
 }
 
 float Axis::ToLocalVelocity(float aVelocityInchesPerMs) {
   ScreenPoint aVelocityPoint = MakePoint(aVelocityInchesPerMs * APZCTreeManager::GetDPI());
   mAsyncPanZoomController->ToLocalScreenCoordinates(&aVelocityPoint, mAsyncPanZoomController->PanStart());
   return aVelocityPoint.Length();
 }
@@ -176,65 +177,74 @@ void Axis::OverscrollBy(ScreenCoord aOve
   }
   mOverscroll += aOverscroll;
 }
 
 ScreenCoord Axis::GetOverscroll() const {
   return mOverscroll;
 }
 
-bool Axis::SampleSnapBack(const TimeDuration& aDelta) {
-  // Apply spring physics to the snap-back as time goes on.
+bool Axis::IsInUnderscroll() const {
+  return mInUnderscroll;
+}
+
+bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
+  // Apply spring physics to the overscroll as time goes on.
   // Note: this method of sampling isn't perfectly smooth, as it assumes
   // a constant velocity over 'aDelta', instead of an accelerating velocity.
   // (The way we applying friction to flings has the same issue.)
   // Hooke's law with damping:
   //   F = -kx - bv
   // where
   //   k is a constant related to the stiffness of the spring
   //     The larger the constant, the stiffer the spring.
   //   x is the displacement of the end of the spring from its equilibrium
   //     In our scenario, it's the amount of overscroll on the axis.
   //   b is a constant that provides damping (friction)
   //   v is the velocity of the point at the end of the spring
   // See http://gafferongames.com/game-physics/spring-physics/
-  const float kSpringStiffness = gfxPrefs::APZOverscrollSnapBackSpringStiffness();
-  const float kSpringFriction = gfxPrefs::APZOverscrollSnapBackSpringFriction();
-  const float kMass = gfxPrefs::APZOverscrollSnapBackMass();
-  float force = -1 * kSpringStiffness * mOverscroll - kSpringFriction * mVelocity;
-  float acceleration = force / kMass;
-  mVelocity += acceleration * aDelta.ToMilliseconds();
-  float displacement = mVelocity * aDelta.ToMilliseconds();
-  if (mOverscroll > 0) {
-    if (displacement > 0) {
-      NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!");
-      return false;
-    }
-    mOverscroll = std::max(mOverscroll + displacement, 0.0f);
-    // Overscroll relieved, do not continue animation.
-    if (mOverscroll == 0.f) {
-      mVelocity = 0;
-      return false;
-    }
-    return true;
-  } else if (mOverscroll < 0) {
-    if (displacement < 0) {
-      NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!");
-      return false;
-    }
-    mOverscroll = std::min(mOverscroll + displacement, 0.0f);
-    // Overscroll relieved, do not continue animation.
-    if (mOverscroll == 0.f) {
-      mVelocity = 0;
-      return false;
-    }
-    return true;
+  const float kSpringStiffness = gfxPrefs::APZOverscrollSpringStiffness();
+  const float kSpringFriction = gfxPrefs::APZOverscrollSpringFriction();
+
+  // Apply spring force.
+  float springForce = -1 * kSpringStiffness * mOverscroll;
+  // Assume unit mass, so force = acceleration.
+  mVelocity += springForce * aDelta.ToMilliseconds();
+
+  // Apply dampening.
+  mVelocity *= pow(double(1 - kSpringFriction), aDelta.ToMilliseconds());
+
+  // Adjust the amount of overscroll based on the velocity.
+  // Note that we allow for oscillations. mInUnderscroll tracks whether
+  // we are currently in a state where we have overshot and the spring is
+  // displaced in the other direction.
+  float oldOverscroll = mOverscroll;
+  mOverscroll += (mVelocity * aDelta.ToMilliseconds());
+  bool signChange = (oldOverscroll * mOverscroll) < 0;
+  if (signChange) {
+    // If the sign of mOverscroll changed, we have either entered underscroll
+    // or exited it.
+    mInUnderscroll = !mInUnderscroll;
   }
-  // No overscroll on this axis, do not continue animation.
-  return false;
+
+  // If both the velocity and the displacement fall below a threshold, stop
+  // the animation so we don't continue doing tiny oscillations that aren't
+  // noticeable.
+  if (fabs(mOverscroll) < gfxPrefs::APZOverscrollStopDistanceThreshold() &&
+      fabs(mVelocity) < gfxPrefs::APZOverscrollStopVelocityThreshold()) {
+    // "Jump" to the at-rest state. The jump shouldn't be noticeable as the
+    // velocity and overscroll are already low.
+    mOverscroll = 0;
+    mVelocity = 0;
+    mInUnderscroll = false;
+    return false;
+  }
+
+  // Otherwise, continue the animation.
+  return true;
 }
 
 bool Axis::IsOverscrolled() const {
   return mOverscroll != 0.f;
 }
 
 void Axis::ClearOverscroll() {
   mOverscroll = 0;
--- a/gfx/layers/apz/src/Axis.h
+++ b/gfx/layers/apz/src/Axis.h
@@ -84,20 +84,26 @@ public:
   void OverscrollBy(ScreenCoord aOverscroll);
 
   /**
    * Return the amount of overscroll on this axis, in Screen pixels.
    */
   ScreenCoord GetOverscroll() const;
 
   /**
+   * Return whether the axis is in underscroll. See |mInUnderscroll|
+   * for a detailed description.
+   */
+  bool IsInUnderscroll() const;
+
+  /**
    * Sample the snap-back animation to relieve overscroll.
    * |aDelta| is the time since the last sample.
    */
-  bool SampleSnapBack(const TimeDuration& aDelta);
+  bool SampleOverscrollAnimation(const TimeDuration& aDelta);
 
   /**
    * Return whether this axis is overscrolled in either direction.
    */
   bool IsOverscrolled() const;
 
   /**
    * Clear any overscroll amount on this axis.
@@ -213,19 +219,54 @@ protected:
   ScreenCoord mStartPos;
   float mVelocity;      // Units: ScreenCoords per millisecond
   bool mAxisLocked;     // Whether movement on this axis is locked.
   AsyncPanZoomController* mAsyncPanZoomController;
   // The amount by which this axis is in overscroll, in Screen coordinates.
   // If this amount is nonzero, the relevant component of
   // mAsyncPanZoomController->mFrameMetrics.mScrollOffset must be at its
   // extreme allowed value in the relevant direction (that is, it must be at
-  // its maximum value if mOverscroll is positive, and at its minimum value
-  // if mOverscroll is negative).
+  // its maximum value if we are overscrolled at our composition length, and
+  // at its minimum value if we are overscrolled at the origin).
+  // Note that if |mInUnderscroll| is true, the interpretation of this field
+  // changes slightly (see below).
   ScreenCoord mOverscroll;
+  // This flag is set when an overscroll animation is in a state where the
+  // spring physics caused a snap-back movement to "overshoot" its target and
+  // as a result the spring is stretched in a direction opposite to the one
+  // when we were in overscroll. We call this situation "underscroll". When in
+  // underscroll, mOverscroll can be nonzero, but rather than being
+  // interpreted as overscroll (stretch) at the other end of the composition
+  // bounds, it's interpeted as an "underscroll" (compression) at the same end.
+  // This table summarizes what the possible combinations of mOverscroll and
+  // mInUnderscroll mean:
+  //
+  //      mOverscroll  |  mInUnderscroll  |    Description
+  //---------------------------------------------------------------------------
+  //       negative    |      false       | The axis is overscrolled at
+  //                   |                  | its origin. A stretch is applied
+  //                   |                  | with the content fixed in place
+  //                   |                  | at the origin.
+  //---------------------------------------------------------------------------
+  //       positive    |      false       | The axis is overscrolled at its
+  //                   |                  | composition end. A stretch is
+  //                   |                  | applied with the content fixed in
+  //                   |                  | place at the composition end.
+  //---------------------------------------------------------------------------
+  //       positive    |      true        | The axis is underscrolled at its
+  //                   |                  | origin. A compression is applied
+  //                   |                  | with the content fixed in place
+  //                   |                  | at the origin.
+  //---------------------------------------------------------------------------
+  //       negative    |      true        | The axis is underscrolled at its
+  //                   |                  | composition end. A compression is
+  //                   |                  | applied with the content fixed in
+  //                   |                  | place at the composition end.
+  //---------------------------------------------------------------------------
+  bool mInUnderscroll;
   // A queue of (timestamp, velocity) pairs; these are the historical
   // velocities at the given timestamps. Timestamps are in milliseconds,
   // velocities are in screen pixels per ms. This member can only be
   // accessed on the controller/UI thread.
   nsTArray<std::pair<uint32_t, float> > mVelocityQueue;
 
   const FrameMetrics& GetFrameMetrics() const;
 
--- a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp
+++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp
@@ -36,17 +36,17 @@ MacIOSurfaceTextureSourceBasic::GetForma
 MacIOSurfaceTextureHostBasic::MacIOSurfaceTextureHostBasic(
     TextureFlags aFlags,
     const SurfaceDescriptorMacIOSurface& aDescriptor
 )
   : TextureHost(aFlags)
 {
   mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
                                          aDescriptor.scaleFactor(),
-                                         aDescriptor.hasAlpha());
+                                         !aDescriptor.isOpaque());
 }
 
 gfx::SourceSurface*
 MacIOSurfaceTextureSourceBasic::GetSurface(gfx::DrawTarget* aTarget)
 {
   if (!mSourceSurface) {
     mSourceSurface = mSurface->GetAsSurface();
   }
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -809,27 +809,22 @@ SharedSurfaceToTexSource(gl::SharedSurfa
   gfx::SurfaceFormat format = abstractSurf->mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
                                                       : gfx::SurfaceFormat::R8G8B8X8;
 
   RefPtr<TextureSource> texSource;
   switch (abstractSurf->mType) {
 #ifdef XP_WIN
     case gl::SharedSurfaceType::EGLSurfaceANGLE: {
       auto surf = gl::SharedSurface_ANGLEShareHandle::Cast(abstractSurf);
-      HANDLE shareHandle = surf->GetShareHandle();
 
       MOZ_ASSERT(compositor->GetBackendType() == LayersBackend::LAYERS_D3D11);
       CompositorD3D11* compositorD3D11 = static_cast<CompositorD3D11*>(compositor);
-      ID3D11Device* d3d = compositorD3D11->GetDevice();
+      RefPtr<ID3D11Texture2D> tex = surf->GetConsumerTexture();
 
-      nsRefPtr<ID3D11Texture2D> tex;
-      HRESULT hr = d3d->OpenSharedResource(shareHandle,
-                                           __uuidof(ID3D11Texture2D),
-                                           getter_AddRefs(tex));
-      if (FAILED(hr)) {
+      if (!tex) {
         NS_WARNING("Failed to open shared resource.");
         break;
       }
       texSource = new DataTextureSourceD3D11(format, compositorD3D11, tex);
       break;
     }
 #endif
     case gl::SharedSurfaceType::GLTextureShare: {
--- a/gfx/layers/d3d9/DeviceManagerD3D9.cpp
+++ b/gfx/layers/d3d9/DeviceManagerD3D9.cpp
@@ -183,27 +183,27 @@ DeviceManagerD3D9::Init()
   HRESULT hr;
 
   if (!GetClassInfoW(GetModuleHandle(nullptr), kClassName, &wc)) {
       ZeroMemory(&wc, sizeof(WNDCLASSW));
       wc.hInstance = GetModuleHandle(nullptr);
       wc.lpfnWndProc = ::DefWindowProc;
       wc.lpszClassName = kClassName;
       if (!RegisterClassW(&wc)) {
-          NS_WARNING("Failed to register window class for DeviceManager.");
+          gfxCriticalError() << "[D3D9] Failed to register class for DeviceManager";
           return false;
       }
   }
 
   mFocusWnd = ::CreateWindowW(kClassName, L"D3D9Window", WS_OVERLAPPEDWINDOW,
                               CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr,
                               nullptr, GetModuleHandle(nullptr), nullptr);
 
   if (!mFocusWnd) {
-    NS_WARNING("Failed to create DeviceManagerD3D9 Window.");
+    gfxCriticalError() << "[D3D9] Failed to create a window";
     return false;
   }
 
   if (gfxPrefs::StereoVideoEnabled()) {
     /* Create an Nv3DVUtils instance */
     if (!mNv3DVUtils) {
       mNv3DVUtils = new Nv3DVUtils();
       if (!mNv3DVUtils) {
@@ -229,30 +229,33 @@ DeviceManagerD3D9::Init()
     if (SUCCEEDED(hr)) {
       mD3D9 = mD3D9Ex;
     }
   }
 #endif
 
   if (!mD3D9) {
     if (!d3d9Create) {
+      gfxCriticalError() << "[D3D9] Failed to load symbols";
       return false;
     }
 
     mD3D9 = dont_AddRef(d3d9Create(D3D_SDK_VERSION));
 
     if (!mD3D9) {
+      gfxCriticalError() << "[D3D9] Failed to create the device";
       return false;
     }
   }
 
   D3DADAPTER_IDENTIFIER9 ident;
   hr = mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &ident);
 
   if (FAILED(hr)) {
+    gfxCriticalError() << "[D3D9] Failed to create the environment";
     return false;
   }
 
   D3DPRESENT_PARAMETERS pp;
   memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
 
   pp.BackBufferWidth = 1;
   pp.BackBufferHeight = 1;
@@ -295,22 +298,23 @@ DeviceManagerD3D9::Init()
                              mFocusWnd,
                              D3DCREATE_FPU_PRESERVE |
                              D3DCREATE_MULTITHREADED |
                              D3DCREATE_MIXED_VERTEXPROCESSING,
                              &pp,
                              getter_AddRefs(mDevice));
 
     if (FAILED(hr)) {
-      NS_WARNING("Failed to create Device for DeviceManagerD3D9.");
+      gfxCriticalError() << "[D3D9] Failed to create the device";
       return false;
     }
   }
 
   if (!VerifyCaps()) {
+    gfxCriticalError() << "[D3D9] insufficient capabilities";
     return false;
   }
 
   /* Grab the associated HMONITOR so that we can find out
    * if it changed later */
   D3DDEVICE_CREATION_PARAMETERS parameters;
   if (FAILED(mDevice->GetCreationParameters(&parameters)))
     return false;
@@ -323,133 +327,153 @@ DeviceManagerD3D9::Init()
   if (mNv3DVUtils) { 
     IUnknown* devUnknown = nullptr; 
     if (mDevice) { 
       mDevice->QueryInterface(IID_IUnknown, (void **)&devUnknown); 
     } 
     mNv3DVUtils->SetDeviceInfo(devUnknown); 
   } 
 
+  auto failCreateShaderMsg = "[D3D9] failed to create a critical resource (shader)";
+
   hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS,
                                    getter_AddRefs(mLayerVS));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPS,
                                   getter_AddRefs(mRGBPS));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)RGBAShaderPS,
                                   getter_AddRefs(mRGBAPS));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)ComponentPass1ShaderPS,
                                   getter_AddRefs(mComponentPass1PS));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)ComponentPass2ShaderPS,
                                   getter_AddRefs(mComponentPass2PS));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPS,
                                   getter_AddRefs(mYCbCrPS));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPS,
                                   getter_AddRefs(mSolidColorPS));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVSMask,
                                    getter_AddRefs(mLayerVSMask));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
   hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVSMask3D,
                                    getter_AddRefs(mLayerVSMask3D));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)RGBShaderPSMask,
                                   getter_AddRefs(mRGBPSMask));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)RGBAShaderPSMask,
                                   getter_AddRefs(mRGBAPSMask));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)RGBAShaderPSMask3D,
                                   getter_AddRefs(mRGBAPSMask3D));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)ComponentPass1ShaderPSMask,
                                   getter_AddRefs(mComponentPass1PSMask));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)ComponentPass2ShaderPSMask,
                                   getter_AddRefs(mComponentPass2PSMask));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)YCbCrShaderPSMask,
                                   getter_AddRefs(mYCbCrPSMask));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   hr = mDevice->CreatePixelShader((DWORD*)SolidColorShaderPSMask,
                                   getter_AddRefs(mSolidColorPSMask));
 
   if (FAILED(hr)) {
+    gfxCriticalError() << failCreateShaderMsg;
     return false;
   }
 
   if (!CreateVertexBuffer()) {
+    gfxCriticalError() << "[D3D9] Failed to create a critical resource (vbo)";
     return false;
   }
 
   hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex));
   if (FAILED(hr)) {
+    gfxCriticalError() << "[D3D9] Failed to set the stream source";
     return false;
   }
 
   D3DVERTEXELEMENT9 elements[] = {
     { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,
       D3DDECLUSAGE_POSITION, 0 },
     D3DDECL_END()
   };
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -48,17 +48,17 @@ struct SurfaceDescriptorD3D10 {
   WindowsHandle handle;
   SurfaceFormat format;
   IntSize size;
 };
 
 struct SurfaceDescriptorMacIOSurface {
   uint32_t surface;
   double scaleFactor;
-  bool hasAlpha;
+  bool isOpaque;
 };
 
 struct SurfaceTextureDescriptor {
   uintptr_t surfTex;
   IntSize size;
 };
 
 struct EGLImageDescriptor {
@@ -69,16 +69,17 @@ struct EGLImageDescriptor {
 struct NewSurfaceDescriptorGralloc {
   MaybeMagicGrallocBufferHandle buffer;
   /**
    * android::GraphicBuffer has a size information. But there are cases
    * that GraphicBuffer's size and actual video's size are different.
    * Extra size member is necessary. See Bug 850566.
    */
   IntSize size;
+  bool isOpaque;
 };
 
 struct SharedSurfaceDescriptor {
   uintptr_t surf;
 };
 
 /**
  * Used for shmem-backed YCbCr and (flavors of) RGBA textures
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -15,37 +15,25 @@
 #include "SharedSurfaceGralloc.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 using namespace android;
 
-GrallocTextureClientOGL::GrallocTextureClientOGL(MaybeMagicGrallocBufferHandle buffer,
-                                                 gfx::IntSize aSize,
-                                                 gfx::BackendType aMoz2dBackend,
-                                                 TextureFlags aFlags)
-: BufferTextureClient(nullptr, gfx::SurfaceFormat::UNKNOWN, aMoz2dBackend, aFlags)
-, mGrallocHandle(buffer)
-, mMappedBuffer(nullptr)
-, mMediaBuffer(nullptr)
-{
-  InitWith(buffer, aSize);
-  MOZ_COUNT_CTOR(GrallocTextureClientOGL);
-}
-
 GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
                                                  gfx::SurfaceFormat aFormat,
                                                  gfx::BackendType aMoz2dBackend,
                                                  TextureFlags aFlags)
 : BufferTextureClient(aAllocator, aFormat, aMoz2dBackend, aFlags)
 , mGrallocHandle(null_t())
 , mMappedBuffer(nullptr)
 , mMediaBuffer(nullptr)
+, mIsOpaque(gfx::IsOpaque(aFormat))
 {
   MOZ_COUNT_CTOR(GrallocTextureClientOGL);
 }
 
 GrallocTextureClientOGL::~GrallocTextureClientOGL()
 {
   MOZ_COUNT_DTOR(GrallocTextureClientOGL);
   ISurfaceAllocator* allocator = GetAllocator();
@@ -84,17 +72,17 @@ GrallocTextureClientOGL::InitWith(MaybeM
 bool
 GrallocTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(IsValid());
   if (!IsAllocated()) {
     return false;
   }
 
-  aOutDescriptor = NewSurfaceDescriptorGralloc(mGrallocHandle, mSize);
+  aOutDescriptor = NewSurfaceDescriptorGralloc(mGrallocHandle, mSize, mIsOpaque);
   return true;
 }
 
 void
 GrallocTextureClientOGL::SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker)
 {
   mRemoveFromCompositableTracker = aTracker;
 }
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -32,20 +32,16 @@ namespace layers {
  *
  * More info about Gralloc here: https://wiki.mozilla.org/Platform/GFX/Gralloc
  *
  * This is only used in Firefox OS
  */
 class GrallocTextureClientOGL : public BufferTextureClient
 {
 public:
-  GrallocTextureClientOGL(MaybeMagicGrallocBufferHandle buffer,
-                          gfx::IntSize aSize,
-                          gfx::BackendType aMoz2dBackend,
-                          TextureFlags aFlags = TextureFlags::DEFAULT);
   GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
                           gfx::SurfaceFormat aFormat,
                           gfx::BackendType aMoz2dBackend,
                           TextureFlags aFlags = TextureFlags::DEFAULT);
 
   ~GrallocTextureClientOGL();
 
   virtual bool Lock(OpenMode aMode) MOZ_OVERRIDE;
@@ -90,16 +86,18 @@ public:
   virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
                                 gfx::IntSize aCbCrSize,
                                 StereoMode aStereoMode) MOZ_OVERRIDE;
 
   bool AllocateForGLRendering(gfx::IntSize aSize);
 
   bool AllocateGralloc(gfx::IntSize aYSize, uint32_t aAndroidFormat, uint32_t aUsage);
 
+  void SetIsOpaque(bool aIsOpaque) { mIsOpaque = aIsOpaque; }
+
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual size_t GetBufferSize() const MOZ_OVERRIDE;
 
   /**
    * Hold android::MediaBuffer.
    * MediaBuffer needs to be add refed to keep MediaBuffer alive
    * during TextureClient is in use.
@@ -142,15 +140,17 @@ protected:
   /**
    * android::GraphicBuffer has a size information. But there are cases
    * that GraphicBuffer's size and actual video's size are different.
    * Extra size member is necessary. See Bug 850566.
    */
   gfx::IntSize mSize;
 
   android::MediaBuffer* mMediaBuffer;
+
+  bool mIsOpaque;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZ_WIDGET_GONK
 #endif
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -241,16 +241,17 @@ GrallocTextureSourceOGL::DeallocateDevic
 GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags,
                                              const NewSurfaceDescriptorGralloc& aDescriptor)
   : TextureHost(aFlags)
   , mGrallocHandle(aDescriptor)
   , mSize(0, 0)
   , mDescriptorSize(aDescriptor.size())
   , mFormat(gfx::SurfaceFormat::UNKNOWN)
   , mEGLImage(EGL_NO_IMAGE)
+  , mIsOpaque(aDescriptor.isOpaque())
 {
   android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
   MOZ_ASSERT(graphicBuffer);
 
   if (graphicBuffer) {
     mFormat =
       SurfaceFormatForAndroidPixelFormat(graphicBuffer->getPixelFormat(),
                                          aFlags & TextureFlags::RB_SWAPPED);
@@ -357,16 +358,19 @@ GrallocTextureHostOGL::DeallocateDeviceD
 
 LayerRenderState
 GrallocTextureHostOGL::GetRenderState()
 {
   android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
 
   if (graphicBuffer) {
     LayerRenderStateFlags flags = LayerRenderStateFlags::LAYER_RENDER_STATE_DEFAULT;
+    if (mIsOpaque) {
+      flags |= LayerRenderStateFlags::OPAQUE;
+    }
     if (mFlags & TextureFlags::NEEDS_Y_FLIP) {
       flags |= LayerRenderStateFlags::Y_FLIPPED;
     }
     if (mFlags & TextureFlags::RB_SWAPPED) {
       flags |= LayerRenderStateFlags::FORMAT_RB_SWAP;
     }
     return LayerRenderState(graphicBuffer,
                             gfx::ThebesIntSize(mDescriptorSize),
--- a/gfx/layers/opengl/GrallocTextureHost.h
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -148,15 +148,16 @@ private:
   RefPtr<GrallocTextureSourceOGL> mTilingTextureSource;
   // Size reported by the GraphicBuffer
   gfx::IntSize mSize;
   // Size reported by TextureClient, can be different in some cases (video?),
   // used by LayerRenderState.
   gfx::IntSize mDescriptorSize;
   gfx::SurfaceFormat mFormat;
   EGLImage mEGLImage;
+  bool mIsOpaque;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
 #endif
--- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp
@@ -50,17 +50,17 @@ bool
 MacIOSurfaceTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(IsValid());
   if (!IsAllocated()) {
     return false;
   }
   aOutDescriptor = SurfaceDescriptorMacIOSurface(mSurface->GetIOSurfaceID(),
                                                  mSurface->GetContentsScaleFactor(),
-                                                 mSurface->HasAlpha());
+                                                 !mSurface->HasAlpha());
   return true;
 }
 
 gfx::IntSize
 MacIOSurfaceTextureClientOGL::GetSize() const
 {
   return gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight());
 }
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -11,17 +11,17 @@ namespace mozilla {
 namespace layers {
 
 MacIOSurfaceTextureHostOGL::MacIOSurfaceTextureHostOGL(TextureFlags aFlags,
                                                        const SurfaceDescriptorMacIOSurface& aDescriptor)
   : TextureHost(aFlags)
 {
   mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
                                          aDescriptor.scaleFactor(),
-                                         aDescriptor.hasAlpha());
+                                         !aDescriptor.isOpaque());
 }
 
 bool
 MacIOSurfaceTextureHostOGL::Lock()
 {
   if (!mCompositor || !mSurface) {
     return false;
   }
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -1014,66 +1014,54 @@ TEST_F(APZCBasicTester, OverScrollPannin
 
   // Pan sufficiently to hit overscroll behavior
   int time = 0;
   int touchStart = 500;
   int touchEnd = 10;
   ApzcPan(apzc, time, touchStart, touchEnd);
   EXPECT_TRUE(apzc->IsOverscrolled());
 
-  // Note that in the calls to SampleContentTransformForFrame below, the time
-  // increment used is sufficiently large for the animation to have completed. However,
-  // any single call to SampleContentTransformForFrame will not finish an animation
-  // *and* also proceed through the following animation, if there is one.
-  // Therefore the minimum number of calls to go from an overscroll-inducing pan
-  // to a reset state is 3; these are documented further below.
-
+  // Check that we recover from overscroll via an animation.
+  const TimeDuration increment = TimeDuration::FromMilliseconds(1);
+  bool recoveredFromOverscroll = false;
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
-
-  // This sample will run to the end of the non-overscrolling fling animation
-  // and will schedule the overscrolling fling animation.
-  apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut);
-  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
-  EXPECT_TRUE(apzc->IsOverscrolled());
-
-  // This sample will run to the end of the overscrolling fling animation and
-  // will schedule the snapback animation.
-  apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(20000), &viewTransformOut, pointOut);
-  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
-  EXPECT_TRUE(apzc->IsOverscrolled());
-
-  // This sample will run to the end of the snapback animation and reset the state.
-  apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(30000), &viewTransformOut, pointOut);
-  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
-  EXPECT_FALSE(apzc->IsOverscrolled());
-
+  while (apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut)) {
+    // The reported scroll offset should be the same throughout.
+    EXPECT_EQ(ScreenPoint(0, 90), pointOut);
+
+    if (!apzc->IsOverscrolled()) {
+      recoveredFromOverscroll = true;
+    }
+
+    testStartTime += increment;
+  }
+  EXPECT_TRUE(recoveredFromOverscroll);
   apzc->AssertStateIsReset();
 }
 
 TEST_F(APZCBasicTester, OverScrollAbort) {
   SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
 
   // Pan sufficiently to hit overscroll behavior
   int time = 0;
   int touchStart = 500;
   int touchEnd = 10;
   ApzcPan(apzc, time, touchStart, touchEnd);
   EXPECT_TRUE(apzc->IsOverscrolled());
 
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
 
-  // This sample call will run to the end of the non-overscrolling fling animation
-  // and will schedule the overscrolling fling animation (see comment in OverScrollPanning
-  // above for more explanation).
+  // This sample call will run to the end of the fling animation
+  // and will schedule the overscroll animation.
   apzc->SampleContentTransformForFrame(testStartTime + TimeDuration::FromMilliseconds(10000), &viewTransformOut, pointOut);
   EXPECT_TRUE(apzc->IsOverscrolled());
 
-  // At this point, we have an active overscrolling fling animation.
+  // At this point, we have an active overscroll animation.
   // Check that cancelling the animation clears the overscroll.
   apzc->CancelAnimation();
   EXPECT_FALSE(apzc->IsOverscrolled());
   apzc->AssertStateIsReset();
 }
 
 TEST_F(APZCBasicTester, OverScrollPanningAbort) {
   SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -672,16 +672,24 @@ gfxContext::Clip(const Rect& rect)
 
 void
 gfxContext::Clip(const gfxRect& rect)
 {
   Clip(ToRect(rect));
 }
 
 void
+gfxContext::Clip(Path* aPath)
+{
+  mDT->PushClip(aPath);
+  AzureState::PushedClip clip = { aPath, Rect(), mTransform };
+  CurrentState().pushedClips.AppendElement(clip);
+}
+
+void
 gfxContext::Clip()
 {
   if (mPathIsRect) {
     MOZ_ASSERT(!mTransformChanged);
 
     AzureState::PushedClip clip = { nullptr, mRect, mTransform };
     CurrentState().pushedClips.AppendElement(clip);
     mDT->PushClipRect(mRect);
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -500,16 +500,17 @@ public:
     void ResetClip();
 
     /**
      * Helper functions that will create a rect path and call Clip().
      * Any current path will be destroyed by these functions!
      */
     void Clip(const Rect& rect);
     void Clip(const gfxRect& rect); // will clip to a rect
+    void Clip(Path* aPath);
 
     /**
      * This will ensure that the surface actually has its clip set.
      * Useful if you are doing native drawing.
      */
     void UpdateSurfaceClip();
 
     /**
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -155,23 +155,22 @@ private:
   DECL_GFX_PREF(Live, "apz.fling_repaint_interval",            APZFlingRepaintInterval, int32_t, 75);
   DECL_GFX_PREF(Once, "apz.fling_stop_on_tap_threshold",       APZFlingStopOnTapThreshold, float, 0.05f);
   DECL_GFX_PREF(Once, "apz.fling_stopped_threshold",           APZFlingStoppedThreshold, float, 0.01f);
   DECL_GFX_PREF(Once, "apz.max_velocity_inches_per_ms",        APZMaxVelocity, float, -1.0f);
   DECL_GFX_PREF(Once, "apz.max_velocity_queue_size",           APZMaxVelocityQueueSize, uint32_t, 5);
   DECL_GFX_PREF(Live, "apz.min_skate_speed",                   APZMinSkateSpeed, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.num_paint_duration_samples",        APZNumPaintDurationSamples, int32_t, 3);
   DECL_GFX_PREF(Live, "apz.overscroll.enabled",                APZOverscrollEnabled, bool, false);
-  DECL_GFX_PREF(Live, "apz.overscroll.fling_friction",         APZOverscrollFlingFriction, float, 0.02f);
-  DECL_GFX_PREF(Live, "apz.overscroll.fling_stopped_threshold", APZOverscrollFlingStoppedThreshold, float, 0.4f);
   DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.overscroll.stretch_factor",         APZOverscrollStretchFactor, float, 0.5f);
-  DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_stiffness", APZOverscrollSnapBackSpringStiffness, float, 0.6f);
-  DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_friction", APZOverscrollSnapBackSpringFriction, float, 0.1f);
-  DECL_GFX_PREF(Live, "apz.overscroll.snap_back.mass",         APZOverscrollSnapBackMass, float, 1000.0f);
+  DECL_GFX_PREF(Live, "apz.overscroll.spring_stiffness",       APZOverscrollSpringStiffness, float, 0.001f);
+  DECL_GFX_PREF(Live, "apz.overscroll.spring_friction",        APZOverscrollSpringFriction, float, 0.015f);
+  DECL_GFX_PREF(Live, "apz.overscroll.stop_distance_threshold", APZOverscrollStopDistanceThreshold, float, 5.0f);
+  DECL_GFX_PREF(Live, "apz.overscroll.stop_velocity_threshold", APZOverscrollStopVelocityThreshold, float, 0.01f);
   DECL_GFX_PREF(Live, "apz.pan_repaint_interval",              APZPanRepaintInterval, int32_t, 250);
   DECL_GFX_PREF(Live, "apz.printtree",                         APZPrintTree, bool, false);
   DECL_GFX_PREF(Live, "apz.smooth_scroll_repaint_interval",    APZSmoothScrollRepaintInterval, int32_t, 75);
   DECL_GFX_PREF(Live, "apz.subframe.enabled",                  APZSubframeEnabled, bool, false);
   DECL_GFX_PREF(Once, "apz.test.logging_enabled",              APZTestLoggingEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.touch_start_tolerance",             APZTouchStartTolerance, float, 1.0f/4.5f);
   DECL_GFX_PREF(Live, "apz.use_paint_duration",                APZUsePaintDuration, bool, true);
   DECL_GFX_PREF(Live, "apz.velocity_bias",                     APZVelocityBias, float, 1.0f);
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1179,16 +1179,18 @@ gfxUtils::EncodeSourceSurface(SourceSurf
     if (imgSize == bufSize) {
       // need a bigger buffer, just double
       bufSize *= 2;
       if (!imgData.resizeUninitialized(bufSize)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
     }
   }
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(!imgData.empty(), NS_ERROR_FAILURE);
 
   if (aBinaryOrData == eBinaryEncode) {
     if (aFile) {
       fwrite(imgData.begin(), 1, imgSize, aFile);
     }
     return NS_OK;
   }
 
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -495,17 +495,17 @@ OnDetached()
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
 }
 
 static bool
 AsmJSHandleExecutionInterrupt()
 {
     AsmJSActivation *act = PerThreadData::innermostAsmJSActivation();
     act->module().setInterrupted(true);
-    bool ret = HandleExecutionInterrupt(act->cx());
+    bool ret = CheckForInterrupt(act->cx());
     act->module().setInterrupted(false);
     return ret;
 }
 
 static int32_t
 CoerceInPlace_ToInt32(MutableHandleValue val)
 {
     JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
@@ -667,18 +667,18 @@ RedirectCall(void *fun, ABIFunctionType 
 }
 
 static void *
 AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
 {
     switch (kind) {
       case AsmJSImm_Runtime:
         return cx->runtimeAddressForJit();
-      case AsmJSImm_RuntimeInterrupt:
-        return cx->runtimeAddressOfInterrupt();
+      case AsmJSImm_RuntimeInterruptUint32:
+        return cx->runtimeAddressOfInterruptUint32();
       case AsmJSImm_StackLimit:
         return cx->stackLimitAddressForJitCode(StackForUntrustedScript);
       case AsmJSImm_ReportOverRecursed:
         return RedirectCall(FuncCast(AsmJSReportOverRecursed), Args_General0);
       case AsmJSImm_OnDetached:
         return RedirectCall(FuncCast(OnDetached), Args_General0);
       case AsmJSImm_HandleExecutionInterrupt:
         return RedirectCall(FuncCast(AsmJSHandleExecutionInterrupt), Args_General0);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -700,23 +700,20 @@ Parser<ParseHandler>::parse(JSObject *ch
                                         &globalsc, /* newDirectives = */ nullptr,
                                         /* staticLevel = */ 0, /* bodyid = */ 0,
                                         /* blockScopeDepth = */ 0);
     if (!globalpc.init(tokenStream))
         return null();
 
     Node pn = statements();
     if (pn) {
-        bool matched;
-        if (!tokenStream.matchToken(&matched, TOK_EOF))
-            return null();
-        if (!matched) {
-            TokenKind tt;
-            if (!tokenStream.peekToken(&tt))
-                return null();
+        TokenKind tt;
+        if (!tokenStream.getToken(&tt))
+            return null();
+        if (tt != TOK_EOF) {
             report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
                    "script", TokenKindToDesc(tt));
             return null();
         }
         if (foldConstants) {
             if (!FoldConstants(context, &pn, this))
                 return null();
         }
@@ -825,23 +822,20 @@ Parser<FullParseHandler>::standaloneFunc
         if (!defineArg(fn, formals[i]))
             return null();
     }
 
     ParseNode *pn = functionBody(Statement, StatementListBody);
     if (!pn)
         return null();
 
-    bool matched;
-    if (!tokenStream.matchToken(&matched, TOK_EOF))
-        return null();
-    if (!matched) {
-        TokenKind tt;
-        if (!tokenStream.peekToken(&tt))
-            return null();
+    TokenKind tt;
+    if (!tokenStream.getToken(&tt))
+        return null();
+    if (tt != TOK_EOF) {
         report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT,
                "function body", TokenKindToDesc(tt));
         return null();
     }
 
     if (!FoldConstants(context, &pn, this))
         return null();
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -541,20 +541,24 @@ class GCRuntime
     void decommitArenas();
     void expireChunksAndArenas(bool shouldShrink, const AutoLockGC &lock);
     void sweepBackgroundThings();
     void assertBackgroundSweepingFinished();
     bool shouldCompact();
 #ifdef JSGC_COMPACTING
     void sweepTypesAfterCompacting(Zone *zone);
     void sweepZoneAfterCompacting(Zone *zone);
-    void compactPhase();
+    void compactPhase(bool lastGC);
     ArenaHeader *relocateArenas();
     void updatePointersToRelocatedCells();
     void releaseRelocatedArenas(ArenaHeader *relocatedList);
+#ifdef DEBUG
+    void protectRelocatedArenas(ArenaHeader *relocatedList);
+    void unprotectRelocatedArenas(ArenaHeader *relocatedList);
+#endif
 #endif
     void finishCollection();
 
     void computeNonIncrementalMarkingForValidation();
     void validateIncrementalMarking();
     void finishMarkingValidation();
 
     void markConservativeStackRoots(JSTracer *trc, bool useSavedRoots);
@@ -844,31 +848,34 @@ class GCRuntime
      * The trace operations to trace embedding-specific GC roots. One is for
      * tracing through black roots and the other is for tracing through gray
      * roots. The black/gray distinction is only relevant to the cycle
      * collector.
      */
     CallbackVector<JSTraceDataOp> blackRootTracers;
     Callback<JSTraceDataOp> grayRootTracer;
 
+    /* Always preserve JIT code during GCs, for testing. */
+    bool                  alwaysPreserveCode;
+
 #ifdef DEBUG
     /*
      * Some regions of code are hard for the static rooting hazard analysis to
      * understand. In those cases, we trade the static analysis for a dynamic
      * analysis. When this is non-zero, we should assert if we trigger, or
      * might trigger, a GC.
      */
     int inUnsafeRegion;
+
+    size_t noGCOrAllocationCheck;
+
+#ifdef JSGC_COMPACTING
+    ArenaHeader* relocatedArenasToRelease;
 #endif
 
-    /* Always preserve JIT code during GCs, for testing. */
-    bool                  alwaysPreserveCode;
-
-#ifdef DEBUG
-    size_t                noGCOrAllocationCheck;
 #endif
 
     /* Synchronize GC heap access between main thread and GCHelperState. */
     PRLock                *lock;
     mozilla::DebugOnly<PRThread *>   lockOwner;
 
     BackgroundAllocTask allocTask;
     GCHelperState helperState;
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -147,17 +147,17 @@ NativeRegExpMacroAssembler::GenerateCode
     frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), ABIStackAlignment) - masm.framePushed();
 
     // Actually emit code to start a new stack frame.
     masm.reserveStack(frameSize);
     masm.checkStackAlignment();
 
     // Check if we have space on the stack.
     Label stack_ok;
-    void *stack_limit = &runtime->mainThread.jitStackLimit;
+    void *stack_limit = runtime->mainThread.addressofJitStackLimit();
     masm.branchPtr(Assembler::Below, AbsoluteAddress(stack_limit), StackPointer, &stack_ok);
 
     // Exit with an exception. There is not enough space on the stack
     // for our working registers.
     masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
     masm.jump(&return_temp0);
 
     masm.bind(&stack_ok);
@@ -497,17 +497,17 @@ NativeRegExpMacroAssembler::AdvanceRegis
 void
 NativeRegExpMacroAssembler::Backtrack()
 {
     JitSpew(SPEW_PREFIX "Backtrack");
 
     // Check for an interrupt.
     Label noInterrupt;
     masm.branch32(Assembler::Equal,
-                  AbsoluteAddress(&runtime->interrupt), Imm32(0),
+                  AbsoluteAddress(runtime->addressOfInterruptUint32()), Imm32(0),
                   &noInterrupt);
     masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
     masm.jump(&exit_label_);
     masm.bind(&noInterrupt);
 
     // Pop code location from backtrack stack and jump to location.
     PopBacktrack(temp0);
     masm.jump(temp0);
--- a/js/src/irregexp/RegExpInterpreter.cpp
+++ b/js/src/irregexp/RegExpInterpreter.cpp
@@ -39,24 +39,33 @@ using namespace js::irregexp;
 
 static const size_t kBitsPerByte = 8;
 static const size_t kBitsPerByteLog2 = 3;
 
 class MOZ_STACK_CLASS RegExpStackCursor
 {
   public:
     explicit RegExpStackCursor(JSContext *cx)
-      : cx(cx), cursor(base())
+      : cx(cx), cursor(nullptr)
     {}
 
+    bool init() {
+        if (!stack.init()) {
+            js_ReportOutOfMemory(cx);
+            return false;
+        }
+        cursor = base();
+        return true;
+    }
+
     bool push(int32_t value) {
         *cursor++ = value;
-        if (cursor >= stack().limit()) {
+        if (cursor >= stack.limit()) {
             int32_t pos = position();
-            if (!stack().grow()) {
+            if (!stack.grow()) {
                 js_ReportOverRecursed(cx);
                 return false;
             }
             setPosition(pos);
         }
         return true;
     }
 
@@ -66,31 +75,32 @@ class MOZ_STACK_CLASS RegExpStackCursor
     }
 
     int32_t peek() {
         MOZ_ASSERT(cursor > base());
         return *(cursor - 1);
     }
 
     int32_t position() {
+        MOZ_ASSERT(cursor >= base());
         return cursor - base();
     }
 
     void setPosition(int32_t position) {
         cursor = base() + position;
-        MOZ_ASSERT(cursor < stack().limit());
+        MOZ_ASSERT(cursor < stack.limit());
     }
 
   private:
     JSContext *cx;
+    RegExpStack stack;
 
     int32_t *cursor;
 
-    RegExpStack &stack() { return cx->runtime()->mainThread.regexpStack; }
-    int32_t *base() { return (int32_t *) stack().base(); }
+    int32_t *base() { return (int32_t *) stack.base(); }
 };
 
 static int32_t
 Load32Aligned(const uint8_t* pc)
 {
     MOZ_ASSERT((reinterpret_cast<uintptr_t>(pc) & 3) == 0);
     return *reinterpret_cast<const int32_t *>(pc);
 }
@@ -110,16 +120,19 @@ irregexp::InterpretCode(JSContext *cx, c
                         size_t length, MatchPairs *matches)
 {
     const uint8_t* pc = byteCode;
 
     uint32_t current_char = current ? chars[current - 1] : '\n';
 
     RegExpStackCursor stack(cx);
 
+    if (!stack.init())
+        return RegExpRunStatus_Error;
+
     int32_t numRegisters = Load32Aligned(pc);
     pc += 4;
 
     Vector<int32_t, 0, SystemAllocPolicy> registers;
     if (!registers.growByUninitialized(numRegisters))
         return RegExpRunStatus_Error;
     for (size_t i = 0; i < (size_t) numRegisters; i++)
         registers[i] = -1;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1091757.js
@@ -0,0 +1,11 @@
+try {
+    (function() {
+	let a = 3;
+	let XY = XY;
+	return function() { return a; };
+    })();
+    assertEq(0, 1);
+} catch(e) {
+    assertEq(e instanceof ReferenceError, true);
+    assertEq(e.message.contains("XY"), true);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1090424.js
@@ -0,0 +1,55 @@
+
+let w
+(function() {
+ testgt1 = function(x) {
+    return (-0x80000000 >= (x | 0))
+}
+ testgt2 = function(x) {
+    return (+0x7fffffff >= (x | 0))
+}
+ testgt3 = function(x) {
+    return ((x | 0) >= -0x80000000)
+}
+ testgt4 = function(x) {
+    return ((x | 0) >= +0x7fffffff)
+}
+
+ testlt1 = function(x) {
+    return (-0x80000000 <= (x | 0))
+}
+ testlt2 = function(x) {
+    return (+0x7fffffff <= (x | 0))
+}
+ testlt3 = function(x) {
+    return ((x | 0) <= -0x80000000)
+}
+ testlt4 = function(x) {
+    return ((x | 0) <= +0x7fffffff)
+}
+
+})()
+assertEq(testgt1(-0x80000000), true);
+assertEq(testgt1(-0x80000000), true);
+assertEq(testgt1(0), false);
+assertEq(testgt2(0x7fffffff), true);
+assertEq(testgt2(0x7fffffff), true);
+assertEq(testgt2(0), true);
+assertEq(testgt3(-0x80000000), true);
+assertEq(testgt3(-0x80000000), true);
+assertEq(testgt3(0), true);
+assertEq(testgt4(0x7fffffff), true);
+assertEq(testgt4(0x7fffffff), true);
+assertEq(testgt4(0), false);
+
+assertEq(testlt1(-0x80000000), true);
+assertEq(testlt1(-0x80000000), true);
+assertEq(testlt1(0), true);
+assertEq(testlt2(0x7fffffff), true);
+assertEq(testlt2(0x7fffffff), true);
+assertEq(testlt2(0), false);
+assertEq(testlt3(-0x80000000), true);
+assertEq(testlt3(-0x80000000), true);
+assertEq(testlt3(0), false);
+assertEq(testlt4(0x7fffffff), true);
+assertEq(testlt4(0x7fffffff), true);
+assertEq(testlt4(0), true);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -491,17 +491,17 @@ BaselineCompiler::emitIC(ICStub *stub, I
 typedef bool (*CheckOverRecursedWithExtraFn)(JSContext *, BaselineFrame *, uint32_t, uint32_t);
 static const VMFunction CheckOverRecursedWithExtraInfo =
     FunctionInfo<CheckOverRecursedWithExtraFn>(CheckOverRecursedWithExtra);
 
 bool
 BaselineCompiler::emitStackCheck(bool earlyCheck)
 {
     Label skipCall;
-    uintptr_t *limitAddr = &cx->runtime()->mainThread.jitStackLimit;
+    void *limitAddr = cx->runtime()->mainThread.addressofJitStackLimit();
     uint32_t slotsSize = script->nslots() * sizeof(Value);
     uint32_t tolerance = earlyCheck ? slotsSize : 0;
 
     masm.movePtr(BaselineStackReg, R1.scratchReg());
 
     // If this is the early stack check, locals haven't been pushed yet.  Adjust the
     // stack pointer to account for the locals that would be pushed before performing
     // the guard around the vmcall to the stack check.
@@ -641,17 +641,17 @@ typedef bool (*InterruptCheckFn)(JSConte
 static const VMFunction InterruptCheckInfo = FunctionInfo<InterruptCheckFn>(InterruptCheck);
 
 bool
 BaselineCompiler::emitInterruptCheck()
 {
     frame.syncStack(0);
 
     Label done;
-    void *interrupt = (void *)&cx->runtime()->interrupt;
+    void *interrupt = cx->runtimeAddressOfInterruptUint32();
     masm.branch32(Assembler::Equal, AbsoluteAddress(interrupt), Imm32(0), &done);
 
     prepareVMCall();
     if (!callVM(InterruptCheckInfo))
         return false;
 
     masm.bind(&done);
     return true;
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -163,22 +163,16 @@ class BaselineFrame
         MOZ_ASSERT((size % sizeof(Value)) == 0);
         return size / sizeof(Value);
     }
     Value *valueSlot(size_t slot) const {
         MOZ_ASSERT(slot < numValueSlots());
         return (Value *)this - (slot + 1);
     }
 
-    Value &unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
-        MOZ_ASSERT(i < script()->nfixedvars());
-        MOZ_ASSERT_IF(checkAliasing, !script()->varIsAliased(i));
-        return *valueSlot(i);
-    }
-
     Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
         MOZ_ASSERT(i < numFormalArgs());
         MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals() &&
                                      !script()->formalIsAliased(i));
         return argv()[i];
     }
 
     Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3742,17 +3742,17 @@ CodeGenerator::visitCheckOverRecursedPar
     // on interrupt or abort, only the stack limit for the main thread
     // is reset, not the worker threads.  See comment in vm/ForkJoin.h
     // for more details.
 
     Register cxReg = ToRegister(lir->forkJoinContext());
     Register tempReg = ToRegister(lir->getTempReg());
 
     masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg);
-    masm.loadPtr(Address(tempReg, offsetof(PerThreadData, jitStackLimit)), tempReg);
+    masm.loadPtr(Address(tempReg, PerThreadData::offsetOfJitStackLimit()), tempReg);
 
     // Conditional forward (unlikely) branch to failure.
     CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir);
     if (!addOutOfLineCode(ool, lir->mir()))
         return false;
 
     masm.branchPtr(Assembler::BelowOrEqual, StackPointer, tempReg, ool->entry());
     masm.checkInterruptFlagPar(tempReg, ool->entry());
@@ -4094,17 +4094,17 @@ CodeGenerator::generateBody()
 
 #ifdef CHECK_OSIPOINT_REGISTERS
             if (iter->safepoint())
                 resetOsiPointRegs(iter->safepoint());
 #endif
 
             if (iter->mirRaw()) {
                 // Only add instructions that have a tracked inline script tree.
-                if (iter->mirRaw()->trackedSite().hasTree()) {
+                if (iter->mirRaw()->trackedTree()) {
                     if (!addNativeToBytecodeEntry(iter->mirRaw()->trackedSite()))
                         return false;
                 }
             }
 
             if (!iter->accept(this))
                 return false;
 
@@ -7330,17 +7330,18 @@ CodeGenerator::generate()
     JitSpew(JitSpew_Codegen, "# Emitting code for script %s:%d",
             gen->info().script()->filename(),
             gen->info().script()->lineno());
 
     // Initialize native code table with an entry to the start of
     // top-level script.
     InlineScriptTree *tree = gen->info().inlineScriptTree();
     jsbytecode *startPC = tree->script()->code();
-    if (!addNativeToBytecodeEntry(BytecodeSite(tree, startPC)))
+    BytecodeSite *startSite = new(gen->alloc()) BytecodeSite(tree, startPC);
+    if (!addNativeToBytecodeEntry(startSite))
         return false;
 
     if (!snapshots_.init())
         return false;
 
     if (!safepoints_.init(gen->alloc(), graph.totalSlotCount()))
         return false;
 
@@ -7389,47 +7390,47 @@ CodeGenerator::generate()
     if (!generateArgumentsChecks(/* bailout = */ false))
         return false;
 #endif
 
     if (!generatePrologue())
         return false;
 
     // Reset native => bytecode map table with top-level script and startPc.
-    if (!addNativeToBytecodeEntry(BytecodeSite(tree, startPC)))
+    if (!addNativeToBytecodeEntry(startSite))
         return false;
 
     if (!generateBody())
         return false;
 
     // Reset native => bytecode map table with top-level script and startPc.
-    if (!addNativeToBytecodeEntry(BytecodeSite(tree, startPC)))
+    if (!addNativeToBytecodeEntry(startSite))
         return false;
 
     if (!generateEpilogue())
         return false;
 
     // Reset native => bytecode map table with top-level script and startPc.
-    if (!addNativeToBytecodeEntry(BytecodeSite(tree, startPC)))
+    if (!addNativeToBytecodeEntry(startSite))
         return false;
 
     if (!generateInvalidateEpilogue())
         return false;
 #if defined(JS_ION_PERF)
     // Note the end of the inline code and start of the OOL code.
     perfSpewer_.noteEndInlineCode(masm);
 #endif
 
     // native => bytecode entries for OOL code will be added
     // by CodeGeneratorShared::generateOutOfLineCode
     if (!generateOutOfLineCode())
         return false;
 
     // Add terminal entry.
-    if (!addNativeToBytecodeEntry(BytecodeSite(tree, startPC)))
+    if (!addNativeToBytecodeEntry(startSite))
         return false;
 
     // Dump Native to bytecode entries to spew.
     dumpNativeToBytecodeEntries();
 
     return !masm.oom();
 }
 
@@ -9783,28 +9784,28 @@ CodeGenerator::visitAssertRangeV(LAssert
 
 bool
 CodeGenerator::visitInterruptCheck(LInterruptCheck *lir)
 {
     OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing());
     if (!ool)
         return false;
 
-    AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterrupt());
+    AbsoluteAddress interruptAddr(GetIonContext()->runtime->addressOfInterruptUint32());
     masm.branch32(Assembler::NotEqual, interruptAddr, Imm32(0), ool->entry());
     masm.bind(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir)
 {
     Register scratch = ToRegister(lir->scratch());
-    masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterrupt), scratch);
-    masm.load8ZeroExtend(Address(scratch, 0), scratch);
+    masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterruptUint32), scratch);
+    masm.load32(Address(scratch, 0), scratch);
     Label rejoin;
     masm.branch32(Assembler::Equal, scratch, Imm32(0), &rejoin);
     {
         uint32_t stackFixup = ComputeByteAlignment(masm.framePushed() + sizeof(AsmJSFrame),
                                                    ABIStackAlignment);
         masm.reserveStack(stackFixup);
         masm.call(lir->funcDesc(), lir->interruptExit());
         masm.freeStack(stackFixup);
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -4,24 +4,23 @@
  * 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 jit_CompileInfo_h
 #define jit_CompileInfo_h
 
 #include "jsfun.h"
 
+#include "jit/IonAllocPolicy.h"
 #include "jit/Registers.h"
 #include "vm/ScopeObject.h"
 
 namespace js {
 namespace jit {
 
-class TempAllocator;
-
 inline unsigned
 StartArgSlot(JSScript *script)
 {
     // Reserved slots:
     // Slot 0: Scope chain.
     // Slot 1: Return value.
 
     // When needed:
@@ -69,17 +68,17 @@ class InlineScriptTree {
       : caller_(caller), callerPc_(callerPc), script_(script),
         children_(nullptr), nextCallee_(nullptr)
     {}
 
     static InlineScriptTree *New(TempAllocator *allocator, InlineScriptTree *caller,
                                  jsbytecode *callerPc, JSScript *script);
 
     InlineScriptTree *addCallee(TempAllocator *allocator, jsbytecode *callerPc,
-                                 JSScript *calleeScript);
+                                JSScript *calleeScript);
 
     InlineScriptTree *caller() const {
         return caller_;
     }
 
     bool isOutermostCaller() const {
         return caller_ == nullptr;
     }
@@ -118,17 +117,18 @@ class InlineScriptTree {
 
     unsigned depth() const {
         if (isOutermostCaller())
             return 1;
         return 1 + caller_->depth();
     }
 };
 
-class BytecodeSite {
+class BytecodeSite : public TempObject
+{
     // InlineScriptTree identifying innermost active function at site.
     InlineScriptTree *tree_;
 
     // Bytecode address within innermost active function.
     jsbytecode *pc_;
 
   public:
     BytecodeSite()
@@ -137,20 +137,16 @@ class BytecodeSite {
 
     BytecodeSite(InlineScriptTree *tree, jsbytecode *pc)
       : tree_(tree), pc_(pc)
     {
         MOZ_ASSERT(tree_ != nullptr);
         MOZ_ASSERT(pc_ != nullptr);
     }
 
-    bool hasTree() const {
-        return tree_ != nullptr;
-    }
-
     InlineScriptTree *tree() const {
         return tree_;
     }
 
     jsbytecode *pc() const {
         return pc_;
     }
 
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -38,17 +38,17 @@ const void *
 CompileRuntime::addressOfJitTop()
 {
     return &runtime()->mainThread.jitTop;
 }
 
 const void *
 CompileRuntime::addressOfJitStackLimit()
 {
-    return &runtime()->mainThread.jitStackLimit;
+    return runtime()->mainThread.addressofJitStackLimit();
 }
 
 const void *
 CompileRuntime::addressOfJSContext()
 {
     return &runtime()->mainThread.jitJSContext;
 }
 
@@ -68,25 +68,25 @@ CompileRuntime::addressOfLastCachedNativ
 const void *
 CompileRuntime::addressOfGCZeal()
 {
     return runtime()->gc.addressOfZealMode();
 }
 #endif
 
 const void *
-CompileRuntime::addressOfInterrupt()
+CompileRuntime::addressOfInterruptUint32()
 {
-    return &runtime()->interrupt;
+    return runtime()->addressOfInterruptUint32();
 }
 
 const void *
-CompileRuntime::addressOfInterruptPar()
+CompileRuntime::addressOfInterruptParUint32()
 {
-    return &runtime()->interruptPar;
+    return runtime()->addressOfInterruptParUint32();
 }
 
 const void *
 CompileRuntime::addressOfThreadPool()
 {
     return &runtime()->threadPool;
 }
 
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -45,18 +45,18 @@ class CompileRuntime
 
     // &GetIonContext()->runtime->nativeIterCache.last
     const void *addressOfLastCachedNativeIterator();
 
 #ifdef JS_GC_ZEAL
     const void *addressOfGCZeal();
 #endif
 
-    const void *addressOfInterrupt();
-    const void *addressOfInterruptPar();
+    const void *addressOfInterruptUint32();
+    const void *addressOfInterruptParUint32();
 
     const void *addressOfThreadPool();
 
     const JitRuntime *jitRuntime();
 
     // Compilation does not occur off thread when the SPS profiler is enabled.
     SPSProfiler &spsProfiler();
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -418,17 +418,17 @@ JitRuntime::ensureIonCodeAccessible(JSRu
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));