Merge m-c to b-s.
authorKyle Huey <khuey@kylehuey.com>
Tue, 14 Aug 2012 11:14:40 -0700
changeset 102440 d1b05e332e4e8ea05d990ca44054c2cc5246b0e2
parent 102439 91711277a553ec1800d0fd7b062512a26b93151a (current diff)
parent 102314 fb2d41f41c15acda67d298774c9e315d9aeb1f16 (diff)
child 102441 d5e42dcb36fdc3171aa43aa6f1b6231bce5114d2
push id13467
push useremorley@mozilla.com
push dateWed, 15 Aug 2012 18:01:05 +0000
treeherdermozilla-inbound@62bb2e74fe67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.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 b-s.
content/base/src/nsDocument.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/generic/nsFrame.cpp
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1120,16 +1120,18 @@ pref("browser.menu.showCharacterEncoding
 
 // Allow using tab-modal prompts when possible.
 pref("prompts.tab_modal.enabled", true);
 // Whether the Panorama should animate going in/out of tabs
 pref("browser.panorama.animate_zoom", true);
 
 // Defines the url to be used for new tabs.
 pref("browser.newtab.url", "about:newtab");
+// Activates preloading of the new tab url.
+pref("browser.newtab.preload", false);
 
 // Toggles the content of 'about:newtab'. Shows the grid when enabled.
 pref("browser.newtabpage.enabled", true);
 
 // Enable the DOM fullscreen API.
 pref("full-screen-api.enabled", true);
 
 // True if the fullscreen API requires approval upon a domain entering fullscreen.
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -592,20 +592,17 @@ var FullScreen = {
     if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) {
       fullscreenctls.removeAttribute("flex");
       document.getElementById("TabsToolbar").appendChild(fullscreenctls);
     }
     else if (fullscreenctls.parentNode.id == "TabsToolbar" && !ctlsOnTabbar) {
       fullscreenctls.setAttribute("flex", "1");
       navbar.appendChild(fullscreenctls);
     }
-
-    var controls = document.getElementsByAttribute("fullscreencontrol", "true");
-    for (var i = 0; i < controls.length; ++i)
-      controls[i].hidden = aShow;
+    fullscreenctls.hidden = aShow;
   }
 };
 XPCOMUtils.defineLazyGetter(FullScreen, "useLionFullScreen", function() {
   // We'll only use OS X Lion full screen if we're
   // * on OS X
   // * on Lion or higher (Darwin 11+)
   // * have fullscreenbutton="true"
 #ifdef XP_MACOSX
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -146,16 +146,22 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 #ifdef MOZ_SAFE_BROWSING
 XPCOMUtils.defineLazyGetter(this, "SafeBrowsing", function() {
   let tmp = {};
   Cu.import("resource://gre/modules/SafeBrowsing.jsm", tmp);
   return tmp.SafeBrowsing;
 });
 #endif
 
+XPCOMUtils.defineLazyGetter(this, "gBrowserNewTabPreloader", function () {
+  let tmp = {};
+  Cu.import("resource://gre/modules/BrowserNewTabPreloader.jsm", tmp);
+  return new tmp.BrowserNewTabPreloader();
+});
+
 let gInitialPages = [
   "about:blank",
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
   "about:sessionrestore"
 ];
 
@@ -209,17 +215,17 @@ XPCOMUtils.defineLazyGetter(this, "PageM
 });
 
 /**
 * We can avoid adding multiple load event listeners and save some time by adding
 * one listener that calls all real handlers.
 */
 function pageShowEventHandlers(event) {
   // Filter out events that are not about the document load we are interested in
-  if (event.originalTarget == content.document) {
+  if (event.target == content.document) {
     charsetLoadListener(event);
     XULBrowserWindow.asyncUpdateUI();
 
     // The PluginClickToPlay events are not fired when navigating using the
     // BF cache. |event.persisted| is true when the page is loaded from the
     // BF cache, so this code reshows the notification if necessary.
     if (event.persisted)
       gPluginHandler.reshowClickToPlayNotification();
@@ -1396,16 +1402,22 @@ var gBrowserInit = {
     if (document.mozFullScreen)
       onMozEnteredDomFullscreen();
 
 #ifdef MOZ_SERVICES_SYNC
     // initialize the sync UI
     gSyncUI.init();
 #endif
 
+    // Don't preload new tab pages when the toolbar is hidden
+    // (i.e. when the current window is a popup window).
+    if (window.toolbar.visible) {
+      gBrowserNewTabPreloader.init(window);
+    }
+
     gBrowserThumbnails.init();
     TabView.init();
 
     setUrlAndSearchBarWidthForConditionalForwardButton();
     window.addEventListener("resize", function resizeHandler(event) {
       if (event.target == window)
         setUrlAndSearchBarWidthForConditionalForwardButton();
     });
@@ -1552,16 +1564,20 @@ var gBrowserInit = {
     CombinedStopReload.uninit();
 
     gGestureSupport.init(false);
 
     FullScreen.cleanup();
 
     Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
 
+    if (!__lookupGetter__("gBrowserNewTabPreloader")) {
+      gBrowserNewTabPreloader.uninit();
+    }
+
     try {
       gBrowser.removeProgressListener(window.XULBrowserWindow);
       gBrowser.removeTabsProgressListener(window.TabsProgressListener);
     } catch (ex) {
     }
 
     PlacesStarButton.uninit();
 
@@ -2510,16 +2526,19 @@ let BrowserOnClick = {
     // If the event came from an ssl error page, it is probably either the "Add
     // Exception…" or "Get me out of here!" button
     if (/^about:certerror/.test(ownerDoc.documentURI)) {
       this.onAboutCertError(originalTarget, ownerDoc);
     }
     else if (/^about:blocked/.test(ownerDoc.documentURI)) {
       this.onAboutBlocked(originalTarget, ownerDoc);
     }
+    else if (/^about:neterror/.test(ownerDoc.documentURI)) {
+      this.onAboutNetError(originalTarget, ownerDoc);
+    }
     else if (/^about:home$/i.test(ownerDoc.documentURI)) {
       this.onAboutHome(originalTarget, ownerDoc);
     }
   },
 
   onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) {
     let elmId = aTargetElm.getAttribute("id");
     let secHistogram = Cc["@mozilla.org/base/telemetry;1"].
@@ -2676,16 +2695,23 @@ let BrowserOnClick = {
       notificationBox.PRIORITY_CRITICAL_HIGH,
       buttons
     );
     // Persist the notification until the user removes so it
     // doesn't get removed on redirects.
     notification.persistence = -1;
   },
 
+  onAboutNetError: function BrowserOnClick_onAboutNetError(aTargetElm, aOwnerDoc) {
+    let elmId = aTargetElm.getAttribute("id");
+    if (elmId != "errorTryAgain" || !/e=netOffline/.test(aOwnerDoc.documentURI))
+      return;
+    Services.io.offline = false;
+  },
+
   onAboutHome: function BrowserOnClick_onAboutHome(aTargetElm, aOwnerDoc) {
     let elmId = aTargetElm.getAttribute("id");
 
     switch (elmId) {
       case "restorePreviousSession":
         let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                  getService(Ci.nsISessionStore);
         if (ss.canRestoreLastSession) {
@@ -4471,21 +4497,21 @@ var TabsProgressListener = {
     // require error page UI to do privileged things, without letting error
     // pages have any privilege themselves.
     // We can't look for this during onLocationChange since at that point the
     // document URI is not yet the about:-uri of the error page.
 
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         Components.isSuccessCode(aStatus) &&
         /^about:/.test(aWebProgress.DOMWindow.document.documentURI)) {
-      aBrowser.addEventListener("click", BrowserOnClick, false);
+      aBrowser.addEventListener("click", BrowserOnClick, true);
       aBrowser.addEventListener("pagehide", function onPageHide(event) {
         if (event.target.defaultView.frameElement)
           return;
-        aBrowser.removeEventListener("click", BrowserOnClick, false);
+        aBrowser.removeEventListener("click", BrowserOnClick, true);
         aBrowser.removeEventListener("pagehide", onPageHide, true);
       }, true);
 
       // We also want to make changes to page UI for unprivileged about pages.
       BrowserOnAboutPageLoad(aWebProgress.DOMWindow.document);
     }
   },
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -783,17 +783,17 @@
             <menuitem id="BMB_unsortedBookmarks"
                       label="&bookmarksMenuButton.unsorted.label;"
                       oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
                       class="menuitem-iconic"/>
           </menupopup>
         </toolbarbutton>
       </toolbaritem>
 
-      <hbox id="window-controls" hidden="true" fullscreencontrol="true" pack="end">
+      <hbox id="window-controls" hidden="true" pack="end">
         <toolbarbutton id="minimize-button"
                        tooltiptext="&fullScreenMinimize.tooltip;"
                        oncommand="window.minimize();"/>
 
         <toolbarbutton id="restore-button"
                        tooltiptext="&fullScreenRestore.tooltip;"
                        oncommand="BrowserFullScreen();"/>
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1378,16 +1378,22 @@
                 Cu.reportError(ex);
               }
             }
 
             // We start our browsers out as inactive, and then maintain
             // activeness in the tab switcher.
             b.docShellIsActive = false;
 
+            // If we just created a new tab that loads the default
+            // newtab url, swap in a preloaded page if possible.
+            if (aURI == BROWSER_NEW_TAB_URL) {
+              gBrowserNewTabPreloader.newTab(t);
+            }
+
             // Check if we're opening a tab related to the current tab and
             // move it to after the current tab.
             // aReferrerURI is null or undefined if the tab is opened from
             // an external application or bookmark, i.e. somewhere other
             // than the current tab.
             if ((aRelatedToCurrent == null ? aReferrerURI : aRelatedToCurrent) &&
                 Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) {
               let newTabPos = (this._lastRelatedTab ||
@@ -1611,16 +1617,21 @@
             // We're committed to closing the tab now.
             // Dispatch a notification.
             // We dispatch it before any teardown so that event listeners can
             // inspect the tab that's about to close.
             var evt = document.createEvent("UIEvent");
             evt.initUIEvent("TabClose", true, false, window, aTabWillBeMoved ? 1 : 0);
             aTab.dispatchEvent(evt);
 
+            // Prevent this tab from showing further dialogs, since we're closing it
+            var windowUtils = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
+                              getInterface(Ci.nsIDOMWindowUtils);
+            windowUtils.preventFurtherDialogs();
+
             // Remove the tab's filter and progress listener.
             const filter = this.mTabFilters[aTab._tPos];
 #ifdef MOZ_E10S_COMPAT
             // Bug 666801 - WebProgress support for e10s
 #else 
             browser.webProgress.removeProgressListener(filter);
 #endif
             filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
@@ -1808,92 +1819,126 @@
               } while (tab && remainingTabs.indexOf(tab) == -1);
             }
 
             this.selectedTab = tab;
           ]]>
         </body>
       </method>
 
+      <method name="swapNewTabWithBrowser">
+        <parameter name="aNewTab"/>
+        <parameter name="aBrowser"/>
+        <body>
+          <![CDATA[
+            // The browser must be standalone.
+            if (aBrowser.getTabBrowser())
+              throw Cr.NS_ERROR_INVALID_ARG;
+
+            // The tab is definitely not loading.
+            aNewTab.removeAttribute("busy");
+            if (aNewTab == this.selectedTab) {
+              this.mIsBusy = false;
+            }
+
+            this._swapBrowserDocShells(aNewTab, aBrowser);
+
+            // Update the new tab's title.
+            this.setTabTitle(aNewTab);
+
+            if (aNewTab == this.selectedTab) {
+              this.updateCurrentBrowser(true);
+            }
+          ]]>
+        </body>
+      </method>
+
       <method name="swapBrowsersAndCloseOther">
         <parameter name="aOurTab"/>
         <parameter name="aOtherTab"/>
         <body>
           <![CDATA[
             // That's gBrowser for the other window, not the tab's browser!
             var remoteBrowser = aOtherTab.ownerDocument.defaultView.gBrowser;
 
             // First, start teardown of the other browser.  Make sure to not
             // fire the beforeunload event in the process.  Close the other
             // window if this was its last tab.
             if (!remoteBrowser._beginRemoveTab(aOtherTab, true, true))
               return;
 
-            // Unhook our progress listener
-            var ourIndex = aOurTab._tPos;
-            const filter = this.mTabFilters[ourIndex];
-            var tabListener = this.mTabListeners[ourIndex];
-            var ourBrowser = this.getBrowserForTab(aOurTab);
-            ourBrowser.webProgress.removeProgressListener(filter);
-            filter.removeProgressListener(tabListener);
-            var tabListenerBlank = tabListener.mBlank;
-
-            var otherBrowser = aOtherTab.linkedBrowser;
-
-            // Restore current registered open URI.
-            if (ourBrowser.registeredOpenURI) {
-              this._placesAutocomplete.unregisterOpenPage(ourBrowser.registeredOpenURI);
-              delete ourBrowser.registeredOpenURI;
-            }
-            if (otherBrowser.registeredOpenURI) {
-              ourBrowser.registeredOpenURI = otherBrowser.registeredOpenURI;
-              delete otherBrowser.registeredOpenURI;
-            }
-
             // Workarounds for bug 458697
             // Icon might have been set on DOMLinkAdded, don't override that.
+            let ourBrowser = this.getBrowserForTab(aOurTab);
+            let otherBrowser = aOtherTab.linkedBrowser;
             if (!ourBrowser.mIconURL && otherBrowser.mIconURL)
               this.setIcon(aOurTab, otherBrowser.mIconURL);
             var isBusy = aOtherTab.hasAttribute("busy");
             if (isBusy) {
               aOurTab.setAttribute("busy", "true");
               this._tabAttrModified(aOurTab);
               if (aOurTab == this.selectedTab)
                 this.mIsBusy = true;
             }
 
-            // Swap the docshells
-            ourBrowser.swapDocShells(otherBrowser);
+            this._swapBrowserDocShells(aOurTab, otherBrowser);
 
             // Finish tearing down the tab that's going away.
             remoteBrowser._endRemoveTab(aOtherTab);
 
-            // Restore the progress listener
-            tabListener = this.mTabProgressListener(aOurTab, ourBrowser,
-                                                    tabListenerBlank);
-            this.mTabListeners[ourIndex] = tabListener;
-            filter.addProgressListener(tabListener,
-              Components.interfaces.nsIWebProgress.NOTIFY_ALL);
-
-            ourBrowser.webProgress.addProgressListener(filter,
-              Components.interfaces.nsIWebProgress.NOTIFY_ALL);
-
             if (isBusy)
               this.setTabTitleLoading(aOurTab);
             else
               this.setTabTitle(aOurTab);
 
             // If the tab was already selected (this happpens in the scenario
             // of replaceTabWithWindow), notify onLocationChange, etc.
             if (aOurTab == this.selectedTab)
               this.updateCurrentBrowser(true);
           ]]>
         </body>
       </method>
 
+      <method name="_swapBrowserDocShells">
+        <parameter name="aOurTab"/>
+        <parameter name="aOtherBrowser"/>
+        <body>
+          <![CDATA[
+            // Unhook our progress listener
+            let index = aOurTab._tPos;
+            const filter = this.mTabFilters[index];
+            let tabListener = this.mTabListeners[index];
+            let ourBrowser = this.getBrowserForTab(aOurTab);
+            ourBrowser.webProgress.removeProgressListener(filter);
+            filter.removeProgressListener(tabListener);
+
+            // Restore current registered open URI.
+            if (ourBrowser.registeredOpenURI) {
+              this._placesAutocomplete.unregisterOpenPage(ourBrowser.registeredOpenURI);
+              delete ourBrowser.registeredOpenURI;
+            }
+            if (aOtherBrowser.registeredOpenURI) {
+              ourBrowser.registeredOpenURI = aOtherBrowser.registeredOpenURI;
+              delete aOtherBrowser.registeredOpenURI;
+            }
+
+            // Swap the docshells
+            ourBrowser.swapDocShells(aOtherBrowser);
+
+            // Restore the progress listener
+            this.mTabListeners[index] = tabListener =
+              this.mTabProgressListener(aOurTab, ourBrowser, false);
+
+            const notifyAll = Ci.nsIWebProgress.NOTIFY_ALL;
+            filter.addProgressListener(tabListener, notifyAll);
+            ourBrowser.webProgress.addProgressListener(filter, notifyAll);
+          ]]>
+        </body>
+      </method>
+
       <method name="reloadAllTabs">
         <body>
           <![CDATA[
             let tabs = this.visibleTabs;
             let l = tabs.length;
             for (var i = 0; i < l; i++) {
               try {
                 this.getBrowserForTab(tabs[i]).reload();
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -194,16 +194,17 @@ endif
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
                  browser_tab_dragdrop.js \
                  browser_tab_dragdrop2.js \
                  browser_tab_dragdrop2_frame1.xul \
                  browser_tabfocus.js \
                  browser_tabs_isActive.js \
                  browser_tabs_owner.js \
+                 browser_unloaddialogs.js \
                  browser_urlbarAutoFillTrimURLs.js \
                  browser_urlbarCopying.js \
                  browser_urlbarEnter.js \
                  browser_urlbarRevert.js \
                  browser_urlbarStop.js \
                  browser_urlbarTrimURLs.js \
                  browser_urlHighlight.js \
                  browser_visibleFindSelection.js \
--- a/browser/base/content/test/browser_bug724239.js
+++ b/browser/base/content/test/browser_bug724239.js
@@ -16,13 +16,18 @@ function test() {
     whenBrowserLoaded(browser, function () {
       ok(!gBrowser.canGoBack, "about:newtab wasn't added to the session history");
       finish();
     });
   });
 }
 
 function whenBrowserLoaded(aBrowser, aCallback) {
+  if (aBrowser.contentDocument.readyState == "complete") {
+    executeSoon(aCallback);
+    return;
+  }
+
   aBrowser.addEventListener("load", function onLoad() {
     aBrowser.removeEventListener("load", onLoad, true);
     executeSoon(aCallback);
   }, true);
 }
--- a/browser/base/content/test/browser_bug763468.js
+++ b/browser/base/content/test/browser_bug763468.js
@@ -62,15 +62,20 @@ function togglePrivateBrowsing(aCallback
   }, topic, false);
 
   pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
 }
 
 function openNewTab(aCallback) {
   // Open a new tab
   BrowserOpenTab();
-  
+
   let browser = gBrowser.selectedBrowser;
+  if (browser.contentDocument.readyState == "complete") {
+    executeSoon(aCallback);
+    return;
+  }
+
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     executeSoon(aCallback);
   }, true);
 }
--- a/browser/base/content/test/browser_bug767836.js
+++ b/browser/base/content/test/browser_bug767836.js
@@ -79,15 +79,20 @@ function togglePrivateBrowsing(aCallback
   }, topic, false);
 
   pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
 }
 
 function openNewTab(aCallback) {
   // Open a new tab
   BrowserOpenTab();
-  
+
   let browser = gBrowser.selectedBrowser;
+  if (browser.contentDocument.readyState == "complete") {
+    executeSoon(aCallback);
+    return;
+  }
+
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     executeSoon(aCallback);
   }, true);
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_unloaddialogs.js
@@ -0,0 +1,134 @@
+function notify(event)
+{
+  if (event.target.location == "about:blank")
+    return;
+
+  var eventname = event.type;
+  if (eventname == "pagehide")
+    details.pagehides++;
+  else if (eventname == "beforeunload")
+    details.beforeunloads++;
+  else if (eventname == "unload")
+    details.unloads++;
+}
+
+var details;
+
+var gUseFrame = false;
+
+const windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+
+const TEST_BASE_URL = "data:text/html,<script>" +
+                      "function note(event) { try { alert(event.type); } catch(ex) { return; } throw 'alert appeared'; }" +
+                      "</script>" +
+                      "<body onpagehide='note(event)' onbeforeunload='alert(event.type);' onunload='note(event)'>";
+
+const TEST_URL = TEST_BASE_URL + "Test</body>";
+const TEST_FRAME_URL = TEST_BASE_URL + "Frames</body>";
+
+function test()
+{
+  waitForExplicitFinish();
+  windowMediator.addListener(promptListener);
+  runTest();
+}
+
+function runTest()
+{
+  details = {
+    testNumber : 0,
+    beforeunloads : 0,
+    pagehides : 0,
+    unloads : 0,
+    prompts : 0
+  };
+
+  var tab = gBrowser.addTab(TEST_URL);
+  gBrowser.selectedTab = tab;
+  tab.linkedBrowser.addEventListener("pageshow", shown, true);
+
+  tab.linkedBrowser.addEventListener("pagehide", notify, true);
+  tab.linkedBrowser.addEventListener("beforeunload", notify, true);
+  tab.linkedBrowser.addEventListener("unload", notify, true);
+}
+
+function shown(event)
+{
+  if (details.testNumber == 0) {
+    var browser;
+    var iframe;
+    if (gUseFrame) {
+      iframe = event.target.createElement("iframe");
+      iframe.src = TEST_FRAME_URL;
+      event.target.documentElement.appendChild(iframe);
+      browser = iframe.contentWindow;
+    }
+    else {
+      browser = gBrowser.selectedTab.linkedBrowser;
+      details.testNumber = 1; // Move onto to the next step immediately
+    }
+  }
+
+  if (details.testNumber == 1) {
+    // Test going to another page
+    executeSoon(function () {
+      const urlToLoad = "data:text/html,<body>Another Page</body>";
+      if (gUseFrame) {
+        event.target.location = urlToLoad;
+      }
+      else {
+        gBrowser.selectedBrowser.loadURI(urlToLoad);
+      }
+    });
+  }
+  else if (details.testNumber == 2) {
+    is(details.pagehides, 1, "pagehides after next page")
+    is(details.beforeunloads, 1, "beforeunloads after next page")
+    is(details.unloads, 1, "unloads after next page")
+    is(details.prompts, 1, "prompts after next page")
+
+    executeSoon(function () gUseFrame ? gBrowser.goBack() : event.target.defaultView.back());
+  }
+  else if (details.testNumber == 3) {
+    is(details.pagehides, 2, "pagehides after back")
+    is(details.beforeunloads, 2, "beforeunloads after back")
+    // No cache, so frame is unloaded
+    is(details.unloads, gUseFrame ? 2 : 1, "unloads after back")
+    is(details.prompts, 1, "prompts after back")
+
+    // Test closing the tab
+    gBrowser.selectedBrowser.removeEventListener("pageshow", shown, true);
+    gBrowser.removeTab(gBrowser.selectedTab);
+
+    // When the frame is present, there is are two beforeunload and prompts,
+    // one for the frame and the other for the parent.
+    is(details.pagehides, 3, "pagehides after close")
+    is(details.beforeunloads, gUseFrame ? 4 : 3, "beforeunloads after close")
+    is(details.unloads, gUseFrame ? 3 : 2, "unloads after close")
+    is(details.prompts, gUseFrame ? 3 : 2, "prompts after close")
+
+    // Now run the test again using a child frame.
+    if (gUseFrame) {
+      windowMediator.removeListener(promptListener);
+      finish();
+    }
+    else {
+      gUseFrame = true;
+      runTest();
+    }
+
+    return;
+  }
+
+  details.testNumber++;
+}
+
+var promptListener = {
+  onWindowTitleChange: function () {},
+  onOpenWindow: function (win) {
+    details.prompts++;
+    let domWin = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    executeSoon(function () { domWin.close() });
+  },
+  onCloseWindow: function () {},
+};
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -198,28 +198,37 @@ function restore() {
 
 /**
  * Creates a new tab containing 'about:newtab'.
  */
 function addNewTabPageTab() {
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:newtab");
   let browser = tab.linkedBrowser;
 
-  // Wait for the new tab page to be loaded.
-  browser.addEventListener("load", function onLoad() {
-    browser.removeEventListener("load", onLoad, true);
-
+  function whenNewTabLoaded() {
     if (NewTabUtils.allPages.enabled) {
       // Continue when the link cache has been populated.
       NewTabUtils.links.populateCache(function () {
         executeSoon(TestRunner.next);
       });
     } else {
       TestRunner.next();
     }
+  }
+
+  // The new tab page might have been preloaded in the background.
+  if (browser.contentDocument.readyState == "complete") {
+    whenNewTabLoaded();
+    return;
+  }
+
+  // Wait for the new tab page to be loaded.
+  browser.addEventListener("load", function onLoad() {
+    browser.removeEventListener("load", onLoad, true);
+    whenNewTabLoaded();
   }, true);
 }
 
 /**
  * Compares the current grid arrangement with the given pattern.
  * @param the pattern (see below)
  * @param the array of sites to compare with (optional)
  *
--- a/browser/components/tabview/test/browser_tabview_bug587503.js
+++ b/browser/components/tabview/test/browser_tabview_bug587503.js
@@ -1,186 +1,107 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
-  requestLongerTimeout(2);
+
+  function moveTabOutOfGroup(aTab, aGroup, aCW, aCallback) {
+    let tabPos = aTab.getBounds().center();
+    let groupPos = aGroup.getBounds();
+    let groupPosX = (groupPos.left + groupPos.right) / 2;
+    let groupPosY = groupPos.bottom + 200;
+    let offsetX = Math.round(groupPosX - tabPos.x);
+    let offsetY = Math.round(groupPosY - tabPos.y);
+
+    simulateDragDrop(aTab, offsetX, offsetY, aCW);
+  }
+
+  function moveTabInGroup(aTab, aIndexTo, aGroup, aCW) {
+    let tabTo = aGroup.getChild(aIndexTo);
+    let tabPos = aTab.getBounds().center();
+    let tabToPos = tabTo.getBounds().center();
+    let offsetX = Math.round(tabToPos.x - tabPos.x);
+    let offsetY = Math.round(tabToPos.y - tabPos.y);
+
+    simulateDragDrop(aTab, offsetX, offsetY, aCW);
+  }
+
+  function getTabNumbers(aGroup) {
+    return aGroup.getChildren().map(function (child) {
+      let url = child.tab.linkedBrowser.currentURI.spec;
+      return url.replace("about:blank#", "");
+    }).join(",");
+  }
+
+  function moveTabs(aGroup, aCW) {
+    // Test 1: Move the last tab to the third position.
+    let tab = aGroup.getChild(6);
+    moveTabInGroup(tab, 2, aGroup, aCW);
+    is(getTabNumbers(aGroup), "0,1,6,2,3,4,5", "Validate tab positions in test 1.");
 
-  newWindowWithTabView(onTabViewWindowLoaded);
+    // Test 2: Move the second tab to the end of the list.
+    tab = aGroup.getChild(1);
+    moveTabInGroup(tab, 6, aGroup, aCW);
+    is(getTabNumbers(aGroup), "0,6,2,3,4,5,1", "Validate tab positions in test 2.");
+
+    // Test 3: Move the fifth tab outside the group.
+    tab = aGroup.getChild(4);
+    moveTabOutOfGroup(tab, aGroup, aCW);
+    is(getTabNumbers(aGroup), "0,6,2,3,5,1", "Validate tab positions in test 3.");
+    is(aCW.GroupItems.groupItems.length, 3, "Validate group count in test 3.");
+
+    // Test 4: Move the fifth tab back into the group, on the second row.
+    waitForTransition(tab, function() {
+      moveTabInGroup(tab, 4, aGroup, aCW);
+      is(getTabNumbers(aGroup), "0,6,2,3,4,5,1", "Validate tab positions in test 4.");
+      is(aCW.GroupItems.groupItems.length, 2, "Validate group count in test 4.");
+      closeGroupItem(aGroup, function() { hideTabView(finish) });
+    });
+  }
+
+  function createGroup(win) {
+    registerCleanupFunction(function() win.close());
+    let cw = win.TabView.getContentWindow();
+    let group = createGroupItemWithTabs(win, 400, 430, 100, [
+      "about:blank#0", "about:blank#1", "about:blank#2", "about:blank#3",
+      "about:blank#4", "about:blank#5", "about:blank#6"
+    ]);
+    let groupSize = group.getChildren().length;
+
+    is(cw.GroupItems.groupItems.length, 2, "Validate group count in tab view.");
+    ok(!group.shouldStack(groupSize), "Check that group should not stack.");
+    is(group._columns, 3, "Check the there should be three columns.");
+
+    moveTabs(group, cw);
+  }
+
+  newWindowWithTabView(createGroup);
 }
 
-function onTabViewWindowLoaded(win) {
-  ok(win.TabView.isVisible(), "Tab View is visible");
-
-  let contentWindow = win.document.getElementById("tab-view").contentWindow;
-  let [originalTab] = win.gBrowser.visibleTabs;
-
-  let currentGroup = contentWindow.GroupItems.getActiveGroupItem();
-
-  // Create a group and make it active
-  let box = new contentWindow.Rect(100, 100, 400, 430);
-  let group = new contentWindow.GroupItem([], { bounds: box });
-  ok(group.isEmpty(), "This group is empty");
-  contentWindow.UI.setActive(group);
-  
-  // Create a bunch of tabs in the group
-  let tabs = [];
-  tabs.push(win.gBrowser.loadOneTab("about:blank#0", {inBackground: true}));
-  tabs.push(win.gBrowser.loadOneTab("about:blank#1", {inBackground: true}));
-  tabs.push(win.gBrowser.loadOneTab("about:blank#2", {inBackground: true}));
-  tabs.push(win.gBrowser.loadOneTab("about:blank#3", {inBackground: true}));
-  tabs.push(win.gBrowser.loadOneTab("about:blank#4", {inBackground: true}));
-  tabs.push(win.gBrowser.loadOneTab("about:blank#5", {inBackground: true}));
-  tabs.push(win.gBrowser.loadOneTab("about:blank#6", {inBackground: true}));
-
-  ok(!group.shouldStack(group._children.length), "Group should not stack.");
-  is(group._columns, 3, "There should be three columns.");
-  
-  // STAGE 1: move the last tab to the third position
-  let currentTarget = tabs[6]._tabViewTabItem;
-  let currentPos = currentTarget.getBounds().center();
-  let targetPos = tabs[2]._tabViewTabItem.getBounds().center();
-  let vector = new contentWindow.Point(targetPos.x - currentPos.x,
-                                       targetPos.y - currentPos.y);
-  checkDropIndexAndDropSpace(currentTarget, group, vector.x, vector.y, contentWindow,
-                             function(index, dropSpaceActiveValues) {
-    // Now: 0, 1, 6, 2, 3, 4, 5
-    is(index, 2, "Tab 6 is now in the third position");
-    is(dropSpaceActiveValues[0], true, "dropSpace was always showing");
+function simulateDragDrop(aTab, aOffsetX, aOffsetY, aCW) {
+  let target = aTab.container;
+  let rect = target.getBoundingClientRect();
+  let startX = (rect.right - rect.left) / 2;
+  let startY = (rect.bottom - rect.top) / 2;
+  let steps = 2;
+  let incrementX = aOffsetX / steps;
+  let incrementY = aOffsetY / steps;
 
-    // STAGE 2: move the second tab to the end of the list
-    let currentTarget = tabs[1]._tabViewTabItem;
-    let currentPos = currentTarget.getBounds().center();
-    // pick a point in that empty bottom part of the group
-    let groupBounds = group.getBounds();
-    let bottomPos = new contentWindow.Point(
-                      (groupBounds.left + groupBounds.right) / 2,
-                      groupBounds.bottom - 15);
-    let vector = new contentWindow.Point(bottomPos.x - currentPos.x,
-                                         bottomPos.y - currentPos.y);
-    checkDropIndexAndDropSpace(currentTarget, group, vector.x, vector.y, contentWindow,
-                               function(index, dropSpaceActiveValues) {
-      // Now: 0, 6, 2, 3, 4, 5, 1
-      is(index, 6, "Tab 1 is now at the end of the group");
-      is(dropSpaceActiveValues[0], true, "dropSpace was always showing");
-    
-      // STAGE 3: move the fifth tab outside the group
-      // Note: there should be room below the active group...
-      let currentTarget = tabs[4]._tabViewTabItem;
-      let currentPos = currentTarget.getBounds().center();
-      // Pick a point below the group.
-      let belowPos = new contentWindow.Point(
-                        (groupBounds.left + groupBounds.right) / 2,
-                        groupBounds.bottom + 300);
-      let vector = new contentWindow.Point(belowPos.x - currentPos.x,
-                                           belowPos.y - currentPos.y);
-      checkDropIndexAndDropSpace(currentTarget, group, vector.x, vector.y, contentWindow,
-                                 function(index, dropSpaceActiveValues) {
-        // Now: 0, 6, 2, 3, 5, 1
-        is(index, -1, "Tab 5 is no longer in the group");
-        contentWindow.Utils.log('dropSpaceActiveValues',dropSpaceActiveValues);
-        is(dropSpaceActiveValues[0], true, "The group began by showing a dropSpace");
-        is(dropSpaceActiveValues[dropSpaceActiveValues.length - 1], false, "In the end, the group was not showing a dropSpace");
-        
-        // We wrap this in a setTimeout with 1000ms delay in order to wait for the
-        // tab to resize, as it does after we drop it in stage 3 outside of the group.
-        setTimeout(function() {
-          // STAGE 4: move the fifth tab back into the group, on the second row.
-          let currentTarget = tabs[4]._tabViewTabItem;
-          let currentPos = currentTarget.getBounds().center();
-          let targetPos = tabs[5]._tabViewTabItem.getBounds().center();
-          // contentWindow.Utils.log(targetPos, currentPos);
-          vector = new contentWindow.Point(targetPos.x - currentPos.x,
-                                               targetPos.y - currentPos.y);
-          // Call with time = 4000
-          checkDropIndexAndDropSpace(currentTarget, group, vector.x, vector.y, contentWindow,
-                                     function(index, dropSpaceActiveValues) {
+  EventUtils.synthesizeMouse(
+    target, startX, startY, { type: "mousedown" }, aCW);
+  for (let i = 1; i <= steps; i++) {
+    EventUtils.synthesizeMouse(
+      target, incrementX + startX, incrementY + startY,
+      { type: "mousemove" }, aCW);
+  };
+  EventUtils.synthesizeMouseAtCenter(target, { type: "mouseup" }, aCW);
+}
 
-            is(group._columns, 3, "There should be three columns.");
-
-            // Now: 0, 6, 2, 3, 4, 5, 1
-            is(index, 4, "Tab 5 is back and again the fifth tab.");
-            contentWindow.Utils.log('dropSpaceActiveValues',dropSpaceActiveValues);
-            is(dropSpaceActiveValues[0], false, "The group began by not showing a dropSpace");
-            is(dropSpaceActiveValues[dropSpaceActiveValues.length - 1], true, "In the end, the group was showing a dropSpace");
-            
-            // Close the window and we're done!
-            win.close();
-            finish();
-          }, 10000, false);
-        }, 2000);
-        
-      });
-    
-    });
-
+function waitForTransition(aTab, aCallback) {
+  let groupContainer = aTab.parent.container;
+  groupContainer.addEventListener("transitionend", function onTransitionEnd(aEvent) {
+    if (aEvent.target == groupContainer) {
+      groupContainer.removeEventListener("transitionend", onTransitionEnd);
+      executeSoon(aCallback);
+    }
   });
 }
-
-function simulateSlowDragDrop(srcElement, offsetX, offsetY, contentWindow, time) {
-  // enter drag mode
-  let dataTransfer;
-
-  let bounds = srcElement.getBoundingClientRect();
-
-  EventUtils.synthesizeMouse(
-    srcElement, 2, 2, { type: "mousedown" }, contentWindow);
-  let event = contentWindow.document.createEvent("DragEvents");
-  event.initDragEvent(
-    "dragenter", true, true, contentWindow, 0, 0, 0, 0, 0,
-    false, false, false, false, 1, null, dataTransfer);
-  srcElement.dispatchEvent(event);
-  
-  let steps = 20;
-  
-  // drag over
-  let moveIncremental = function moveIncremental(i, steps) {
-    // calculate how much to move
-    let offsetXDiff = Math.round(i * offsetX / steps) - Math.round((i - 1) * offsetX / steps);
-    let offsetYDiff = Math.round(i * offsetY / steps) - Math.round((i - 1) * offsetY / steps);
-    // contentWindow.Utils.log('step', offsetXDiff, offsetYDiff);
-    // simulate mousemove
-    EventUtils.synthesizeMouse(
-      srcElement, offsetXDiff + 2, offsetYDiff + 2,
-      { type: "mousemove" }, contentWindow);
-    // simulate dragover
-    let event = contentWindow.document.createEvent("DragEvents");
-    event.initDragEvent(
-      "dragover", true, true, contentWindow, 0, 0, 0, 0, 0,
-      false, false, false, false, 0, null, dataTransfer);
-    srcElement.dispatchEvent(event);
-    let bounds = srcElement.getBoundingClientRect();
-    // contentWindow.Utils.log(i, 'center', bounds.left + bounds.width / 2, bounds.top + bounds.height / 2);
-  };
-  for (let i = 1; i <= steps; i++)
-    setTimeout(moveIncremental, i / (steps + 1) * time, i, steps);
-
-  // drop
-  let finalDrop = function finalDrop() {
-    EventUtils.synthesizeMouseAtCenter(srcElement, { type: "mouseup" }, contentWindow);
-    event = contentWindow.document.createEvent("DragEvents");
-    event.initDragEvent(
-      "drop", true, true, contentWindow, 0, 0, 0, 0, 0,
-      false, false, false, false, 0, null, dataTransfer);
-    srcElement.dispatchEvent(event);
-    contentWindow.iQ(srcElement).css({border: 'green 1px solid'});
-  }
-  setTimeout(finalDrop, time);
-}
-
-function checkDropIndexAndDropSpace(item, group, offsetX, offsetY, contentWindow, callback, time) {
-  contentWindow.UI.setActive(item);
-  let dropSpaceActiveValues = [];
-  let recordDropSpaceValue = function() {
-    dropSpaceActiveValues.push(group._dropSpaceActive);
-  };
-
-  let onDrop = function() {
-    item.container.removeEventListener('dragover', recordDropSpaceValue, false);
-    item.container.removeEventListener('drop', onDrop, false);
-    let index = group._children.indexOf(item);
-    callback(index, dropSpaceActiveValues);
-  };
-  item.container.addEventListener('dragover', recordDropSpaceValue, false);
-  item.container.addEventListener('drop', onDrop, false);
-  simulateSlowDragDrop(item.container, offsetX, offsetY, contentWindow, time || 1000);
-}
--- a/browser/components/tabview/test/browser_tabview_bug626455.js
+++ b/browser/components/tabview/test/browser_tabview_bug626455.js
@@ -57,19 +57,16 @@ function testStayOnPage() {
 
   closeGroupItem(activeGroup);
 }
 
 function testLeavePage() {
   let dialogsAccepted = 0;
 
   whenDialogOpened(function onDialogOpened(dialog) {
-    if (++dialogsAccepted < 3)
-      whenDialogOpened(onDialogOpened);
-
     // Leave page
     dialog.acceptDialog();
   });
 
   whenGroupClosed(activeGroup, finishTest);
   closeGroupItem(activeGroup);
 }
 
--- a/browser/devtools/webconsole/WebConsoleUtils.jsm
+++ b/browser/devtools/webconsole/WebConsoleUtils.jsm
@@ -948,68 +948,77 @@ function JSPropertyProvider(aScope, aInp
     return null;
   }
 
   // Skip Iterators and Generators.
   if (WCU.isIteratorOrGenerator(obj)) {
     return null;
   }
 
-  let matches = Object.keys(getMatchedProps(obj, matchProp));
+  let matches = Object.keys(getMatchedProps(obj, {matchProp:matchProp}));
 
   return {
     matchProp: matchProp,
     matches: matches.sort(),
   };
 }
 
 /**
- * Get all accessible properties on this object.
+ * Get all accessible properties on this JS value.
  * Filter those properties by name.
  * Take only a certain number of those.
  *
- * @param object obj
- *        Object whose properties we want to collect.
+ * @param mixed aObj
+ *        JS value whose properties we want to collect.
  *
- * @param string matchProp
- *        Filter for properties that match this one.
- *        Defaults to the empty string (which always matches).
+ * @param object aOptions
+ *        Options that the algorithm takes.
+ *        - matchProp (string): Filter for properties that match this one.
+ *          Defaults to the empty string (which always matches).
  *
  * @return object
  *         Object whose keys are all accessible properties on the object.
  */
-function getMatchedProps(aObj, aMatchProp = "")
+function getMatchedProps(aObj, aOptions = {matchProp: ""})
 {
+  // Argument defaults.
+  aOptions.matchProp = aOptions.matchProp || "";
+
+  if (aObj == null) { return {}; }
+  try {
+    Object.getPrototypeOf(aObj);
+  } catch(e) {
+    aObj = aObj.constructor.prototype;
+  }
   let c = MAX_COMPLETIONS;
   let names = {};   // Using an Object to avoid duplicates.
-  let ownNames = Object.getOwnPropertyNames(aObj);
-  for (let i = 0; i < ownNames.length; i++) {
-    if (ownNames[i].indexOf(aMatchProp) == 0) {
-      if (names[ownNames[i]] != true) {
-        c--;
-        if (c < 0) {
-          return names;
-        }
+
+  // We need to go up the prototype chain.
+  let ownNames = null;
+  while (aObj !== null) {
+    ownNames = Object.getOwnPropertyNames(aObj);
+    for (let i = 0; i < ownNames.length; i++) {
+      // Filtering happens here.
+      // If we already have it in, no need to append it.
+      if (ownNames[i].indexOf(aOptions.matchProp) != 0 ||
+          names[ownNames[i]] == true) {
+        continue;
+      }
+      c--;
+      if (c < 0) {
+        return names;
+      }
+      // If it is an array index, we can't take it.
+      // This uses a trick: converting a string to a number yields NaN if
+      // the operation failed, and NaN is not equal to itself.
+      if (+ownNames[i] != +ownNames[i]) {
         names[ownNames[i]] = true;
       }
     }
+    aObj = Object.getPrototypeOf(aObj);
   }
 
-  // We need to recursively go up the prototype chain.
-  aObj = Object.getPrototypeOf(aObj);
-  if (aObj !== null) {
-    let parentScope = getMatchedProps(aObj, aMatchProp);
-    for (let name in parentScope) {
-      if (names[name] != true) {
-        c--;
-        if (c < 0) {
-          return names;
-        }
-        names[name] = true;
-      }
-    }
-  }
   return names;
 }
 
 
 return JSPropertyProvider;
 })(WebConsoleUtils);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
@@ -190,20 +190,47 @@ function testReturnKey()
 
       ok(!popup.isOpen, "popup is not open after VK_RETURN");
 
       is(inputNode.value, "window.foobarBug585991.__defineSetter__",
          "completion was successful after VK_RETURN");
 
       ok(!completeNode.value, "completeNode is empty");
 
-      executeSoon(finishTest);
+      dontShowArrayNumbers();
     }, false);
 
     EventUtils.synthesizeKey("VK_RETURN", {});
   }, false);
 
   executeSoon(function() {
     jsterm.setInputValue("window.foobarBug58599");
     EventUtils.synthesizeKey("1", {});
     EventUtils.synthesizeKey(".", {});
   });
 }
+
+function dontShowArrayNumbers()
+{
+  content.wrappedJSObject.foobarBug585991 = ["Sherlock Holmes"];
+
+  let jsterm = HUD.jsterm;
+  let popup = jsterm.autocompletePopup;
+  let completeNode = jsterm.completeNode;
+
+  popup._panel.addEventListener("popupshown", function onShown() {
+    popup._panel.removeEventListener("popupshown", onShown, false);
+
+    let sameItems = popup.getItems().map(function(e) {return e.label;});
+    ok(!sameItems.some(function(prop, index) { prop === "0"; }),
+       "Completing on an array doesn't show numbers.");
+
+    popup._panel.addEventListener("popuphidden", consoleOpened, false);
+
+    EventUtils.synthesizeKey("VK_TAB", {});
+
+    executeSoon(finishTest);
+  }, false);
+
+  jsterm.setInputValue("window.foobarBug585991");
+  EventUtils.synthesizeKey(".", {});
+}
+
--- a/browser/devtools/webconsole/test/browser_webconsole_completion.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js
@@ -93,13 +93,20 @@ function testCompletion(hud) {
 
   // Test multi-line completion works
   input.value =                 "console.log('one');\nconsol";
   jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
   yield;
 
   is(jsterm.completeNode.value, "                   \n      e", "multi-line completion");
 
+  // Test non-object autocompletion.
+  input.value = "Object.name.sl";
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield;
+
+  is(jsterm.completeNode.value, "              ice", "non-object completion");
+
   testDriver = jsterm = input = null;
   executeSoon(finishTest);
   yield;
 }
 
--- a/browser/devtools/webconsole/webconsole.xul
+++ b/browser/devtools/webconsole/webconsole.xul
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <!DOCTYPE window [
 <!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd">
 %webConsoleDTD;
 ]>
-<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/webconsole.css"
                  type="text/css"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="&window.title;"
         windowtype="devtools:webconsole"
         persist="screenX screenY width height sizemode">
   <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
new file mode 100644
--- /dev/null
+++ b/browser/modules/BrowserNewTabPreloader.jsm
@@ -0,0 +1,160 @@
+/* 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";
+
+let EXPORTED_SYMBOLS = ["BrowserNewTabPreloader"];
+
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+const PREF_NEWTAB_URL = "browser.newtab.url";
+const PREF_NEWTAB_PRELOAD = "browser.newtab.preload";
+
+function BrowserNewTabPreloader() {
+}
+
+BrowserNewTabPreloader.prototype = {
+  _url: null,
+  _window: null,
+  _browser: null,
+  _enabled: null,
+
+  init: function Preloader_init(aWindow) {
+    if (this._window) {
+      return;
+    }
+
+    this._window = aWindow;
+    this._enabled = Preferences.enabled;
+    this._url = Preferences.url;
+    Preferences.addObserver(this);
+
+    if (this._enabled) {
+      this._createBrowser();
+    }
+  },
+
+  uninit: function Preloader_uninit() {
+    if (!this._window) {
+      return;
+    }
+
+    if (this._browser) {
+      this._browser.parentNode.removeChild(this._browser);
+      this._browser = null;
+    }
+
+    this._window = null;
+    Preferences.removeObserver(this);
+  },
+
+  newTab: function Preloader_newTab(aTab) {
+    if (!this._window || !this._enabled) {
+      return;
+    }
+
+    let tabbrowser = this._window.gBrowser;
+    if (tabbrowser && this._isPreloaded()) {
+      tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
+    }
+  },
+
+  observe: function Preloader_observe(aEnabled, aURL) {
+    if (this._url != aURL) {
+      this._url = aURL;
+
+      if (this._enabled && aEnabled) {
+        // We're still enabled but the newtab URL has changed.
+        this._browser.setAttribute("src", aURL);
+        return;
+      }
+    }
+
+    if (this._enabled && !aEnabled) {
+      // We got disabled. Remove the browser.
+      this._browser.parentNode.removeChild(this._browser);
+      this._browser = null;
+      this._enabled = false;
+    } else if (!this._enabled && aEnabled) {
+      // We got enabled. Create a browser and start preloading.
+      this._createBrowser();
+      this._enabled = true;
+    }
+  },
+
+  _createBrowser: function Preloader_createBrowser() {
+    let document = this._window.document;
+    this._browser = document.createElement("browser");
+    this._browser.setAttribute("type", "content");
+    this._browser.setAttribute("src", this._url);
+    this._browser.collapsed = true;
+
+    let panel = document.getElementById("browser-panel");
+    panel.appendChild(this._browser);
+  },
+
+  _isPreloaded: function Preloader_isPreloaded()  {
+    return this._browser &&
+           this._browser.contentDocument &&
+           this._browser.contentDocument.readyState == "complete" &&
+           this._browser.currentURI.spec == this._url;
+  }
+};
+
+let Preferences = {
+  _observers: [],
+
+  get _branch() {
+    delete this._branch;
+    return this._branch = Services.prefs.getBranch("browser.newtab.");
+  },
+
+  get enabled() {
+    if (!this._branch.getBoolPref("preload")) {
+      return false;
+    }
+
+    if (this._branch.prefHasUserValue("url")) {
+      return false;
+    }
+
+    let url = this.url;
+    return url && url != "about:blank";
+  },
+
+  get url() {
+    return this._branch.getCharPref("url");
+  },
+
+  addObserver: function Preferences_addObserver(aObserver) {
+    let index = this._observers.indexOf(aObserver);
+    if (index == -1) {
+      if (this._observers.length == 0) {
+        this._branch.addObserver("", this, false);
+      }
+      this._observers.push(aObserver);
+    }
+  },
+
+  removeObserver: function Preferences_removeObserver(aObserver) {
+    let index = this._observers.indexOf(aObserver);
+    if (index > -1) {
+      if (this._observers.length == 1) {
+        this._branch.removeObserver("", this);
+      }
+      this._observers.splice(index, 1);
+    }
+  },
+
+  observe: function Preferences_observe(aSubject, aTopic, aData) {
+    let url = this.url;
+    let enabled = this.enabled;
+
+    for (let obs of this._observers) {
+      obs.observe(enabled, url);
+    }
+  }
+};
--- a/browser/modules/Makefile.in
+++ b/browser/modules/Makefile.in
@@ -9,16 +9,17 @@ VPATH   = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/config.mk
 
 TEST_DIRS += test
 
 EXTRA_JS_MODULES = \
+	BrowserNewTabPreloader.jsm \
 	openLocationLastURL.jsm \
 	NetworkPrioritizer.jsm \
 	NewTabUtils.jsm \
 	offlineAppCache.jsm \
 	TelemetryTimestamps.jsm \
 	Social.jsm \
 	webappsUI.jsm \
 	$(NULL)
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -2559,21 +2559,16 @@ stack[anonid=browserStack][responsivemod
 .web-console-frame[animated] {
   transition: height 100ms;
 }
 
 .web-console-splitter {
   box-shadow: 0 -1px 0 0 ThreeDShadow inset, 0 0 0 10px -moz-Dialog inset;
 }
 
-.web-console-panel {
-  -moz-appearance: none;
-  background-color: white;
-}
-
 
 /* Developer Toolbar */
 
 .developer-toolbar-button {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3326,21 +3326,16 @@ stack[anonid=browserStack][responsivemod
 }
 
 .web-console-splitter {
   border-bottom: solid #a5a5a5 1px;
   background: url("chrome://global/skin/splitter/dimple.png") no-repeat center,
     -moz-linear-gradient(top, #fcfcfc, #dfdfdf);
 }
 
-.web-console-panel {
-  -moz-appearance: none;
-  background-color: white;
-}
-
 /* Developer Toolbar */
 
 .developer-toolbar-button {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border-radius: @toolbarbuttonCornerRadius@;
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3240,21 +3240,16 @@ stack[anonid=browserStack][responsivemod
 .web-console-frame[animated] {
   transition: height 100ms;
 }
 
 .web-console-splitter {
   border-top: none;
 }
 
-.web-console-panel {
-  -moz-appearance: none;
-  background-color: white;
-}
-
 /* Developer Toolbar */
 
 .developer-toolbar-button {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border-radius: 3px;
--- a/build/mobile/robocop/FennecNativeDriver.java.in
+++ b/build/mobile/robocop/FennecNativeDriver.java.in
@@ -13,16 +13,17 @@ import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.nio.IntBuffer;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import java.lang.Class;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.InvocationHandler;
 import java.lang.Long;
 
@@ -417,16 +418,30 @@ public class FennecNativeDriver implemen
         String[] lines = data.split("\n");
         for (int i = 0; i < lines.length; i++) {
             String[] parts = lines[i].split("=");
             retVal.put(parts[0].trim(), parts[1].trim());
         }
         return retVal;
     }
 
+    public static void logAllStackTraces(LogLevel level) {
+        StringBuffer sb = new StringBuffer();
+        sb.append("Dumping ALL the threads!\n");
+        Map<Thread, StackTraceElement[]> allStacks = Thread.getAllStackTraces();
+        for (Thread t : allStacks.keySet()) {
+            sb.append(t.toString()).append('\n');
+            for (StackTraceElement ste : allStacks.get(t)) {
+                sb.append(ste.toString()).append('\n');
+            }
+            sb.append('\n');
+        }
+        log(level, sb.toString());
+    }
+
     /** 
      *  Set the filename used for logging. If the file already exists, delete it
      *  as a safe-guard against accidentally appending to an old log file.
      */
     public static void setLogFile(String filename) {
         mLogFile = filename;
         File file = new File(mLogFile);
         if (file.exists()) {
--- a/build/mobile/robocop/FennecNativeElement.java.in
+++ b/build/mobile/robocop/FennecNativeElement.java.in
@@ -64,16 +64,17 @@ public class FennecNativeElement impleme
                     }
                 }
             });
         try {
             // Wait for the UiThread code to finish running
             if (syncQueue.poll(MAX_WAIT_MS, TimeUnit.MILLISECONDS) == null) {
                 FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, 
                     "click: time-out waiting for UI thread");
+                FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
             }
         } catch (InterruptedException e) {
             FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, e);
         }
         return mClickSuccess;
     }
 
     private Object mText;
@@ -116,16 +117,17 @@ public class FennecNativeElement impleme
                 } // end of run() method definition
             } // end of anonymous Runnable object instantiation
         );
         try {     
             // Wait for the UiThread code to finish running
             if (syncQueue.poll(MAX_WAIT_MS, TimeUnit.MILLISECONDS) == null) {
                 FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, 
                     "getText: time-out waiting for UI thread");
+                FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
             }
         } catch (InterruptedException e) {
             FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, e);
         }
         if (mText == null) {
             FennecNativeDriver.log(FennecNativeDriver.LogLevel.WARN,
                 "getText: Text is null for view "+mId);
             return null;
@@ -152,16 +154,17 @@ public class FennecNativeElement impleme
                     }
                 }
             });
         try {
             // Wait for the UiThread code to finish running
             if (syncQueue.poll(MAX_WAIT_MS, TimeUnit.MILLISECONDS) == null) {
                 FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, 
                     "isDisplayed: time-out waiting for UI thread");
+                FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
             }
         } catch (InterruptedException e) {
             FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR, e);
         }
         return mDisplayed;
     }
 
 }
--- a/caps/idl/nsIPrincipal.idl
+++ b/caps/idl/nsIPrincipal.idl
@@ -235,16 +235,28 @@ interface nsIPrincipal : nsISerializable
 
     /**
      * Shows the status of the app.
      * Can be: APP_STATUS_NOT_INSTALLED, APP_STATUS_INSTALLED,
      *         APP_STATUS_PRIVILEGED or APP_STATUS_CERTIFIED.
      */
     readonly attribute unsigned short appStatus;
 
+    %{C++
+    PRUint16 GetAppStatus()
+    {
+      PRUint16 appStatus;
+      nsresult rv = GetAppStatus(&appStatus);
+      if (NS_FAILED(rv)) {
+        return APP_STATUS_NOT_INSTALLED;
+      }
+      return appStatus;
+    }
+    %}
+
     /**
      * Returns the app id the principal is in, or returns
      * nsIScriptSecurityManager::NO_APP_ID if this principal isn't part of an
      * app.
      */
     readonly attribute unsigned long appId;
 
     /**
--- a/config/config.mk
+++ b/config/config.mk
@@ -82,30 +82,22 @@ BUILD_TOOLS	= $(WIN_TOP_SRC)/build/unix
 else
 win_srcdir	:= $(srcdir)
 BUILD_TOOLS	= $(topsrcdir)/build/unix
 endif
 
 CONFIG_TOOLS	= $(MOZ_BUILD_ROOT)/config
 AUTOCONF_TOOLS	= $(topsrcdir)/build/autoconf
 
-ifeq ($(OS_ARCH),QNX)
-ifeq ($(OS_TARGET),NTO)
-LD		:= qcc -Vgcc_ntox86 -nostdlib
-else
-LD		:= $(CC)
-endif
-endif
-
 #
 # Strip off the excessively long version numbers on these platforms,
 # but save the version to allow multiple versions of the same base
 # platform to be built in the same tree.
 #
-ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD OSF1 SunOS,$(OS_ARCH)))
+ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD SunOS,$(OS_ARCH)))
 OS_RELEASE	:= $(basename $(OS_RELEASE))
 
 # Allow the user to ignore the OS_VERSION, which is usually irrelevant.
 ifdef WANT_MOZILLA_CONFIG_OS_VERSION
 OS_VERS		:= $(suffix $(OS_RELEASE))
 OS_VERSION	:= $(shell echo $(OS_VERS) | sed 's/-.*//')
 endif
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -496,27 +496,16 @@ ifdef IS_COMPONENT
 ifneq ($(HAS_EXTRAEXPORTS),1)
 MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 endif # HAS_EXTRAEXPORTS
 endif # IS_COMPONENT
 endif # AIX
 
 #
-# OSF1: add -B symbolic flag for components
-#
-ifeq ($(OS_ARCH),OSF1)
-ifdef IS_COMPONENT
-ifeq ($(GNU_CC)$(GNU_CXX),)
-EXTRA_DSO_LDOPTS += -B symbolic
-endif
-endif
-endif
-
-#
 # Linux: add -Bsymbolic flag for components
 #
 ifeq ($(OS_ARCH),Linux)
 ifdef IS_COMPONENT
 EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic
 endif
 endif
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -9120,17 +9120,17 @@ nsDocument::RequestFullScreen(Element* a
 
   // If this document hasn't already been approved in this session,
   // check to see if the user has granted the fullscreen access
   // to the document's principal's host, if it has one. Note that documents
   // in web apps which are the same origin as the web app are considered
   // trusted and so are automatically approved.
   if (!mIsApprovedForFullscreen) {
     mIsApprovedForFullscreen =
-      GetWindow()->IsInAppOrigin() ||
+      NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED ||
       nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen");
   }
 
   // If this document, or a document with the same principal has not
   // already been approved for fullscreen this fullscreen-session, dispatch
   // an event so that chrome knows to pop up a warning/approval UI.
   nsCOMPtr<nsIDocument> previousFullscreenDoc(do_QueryReferent(sFullScreenDoc));
   // Note previousFullscreenDoc=nullptr upon first entry, so we always
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -283,16 +283,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrame
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
   NS_INTERFACE_MAP_ENTRY(nsIContentViewManager)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
 NS_INTERFACE_MAP_END
 
 nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
   : mOwnerContent(aOwner)
+  , mDetachedSubdocViews(nullptr)
   , mDepthTooGreat(false)
   , mIsTopLevelContent(false)
   , mDestroyCalled(false)
   , mNeedsAsyncDestroy(false)
   , mInSwap(false)
   , mInShow(false)
   , mHideCalled(false)
   , mNetworkCreated(aNetworkCreated)
@@ -2369,17 +2370,26 @@ nsFrameLoader::GetOwnerElement(nsIDOMEle
 
 void
 nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
 {
   MOZ_ASSERT(!mRemoteBrowser);
   MOZ_ASSERT(!mCurrentRemoteFrame);
   mRemoteBrowser = static_cast<TabParent*>(aTabParent);
 
-  EnsureMessageManager();
-  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
-  if (OwnerIsBrowserFrame() && os) {
-    mRemoteBrowserInitialized = true;
-    os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
-                        "remote-browser-frame-shown", NULL);
-  }
+  ShowRemoteFrame(nsIntSize(0, 0));
 }
 
+void
+nsFrameLoader::SetDetachedSubdocView(nsIView* aDetachedViews,
+                                     nsIDocument* aContainerDoc)
+{
+  mDetachedSubdocViews = aDetachedViews;
+  mContainerDocWhileDetached = aContainerDoc;
+}
+
+nsIView*
+nsFrameLoader::GetDetachedSubdocView(nsIDocument** aContainerDoc) const
+{
+  NS_IF_ADDREF(*aContainerDoc = mContainerDocWhileDetached);
+  return mDetachedSubdocViews;
+}
+
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -263,16 +263,35 @@ public:
    *
    * This will assert if mRemoteBrowser or mCurrentRemoteFrame is non-null.  In
    * practice, this means you can't have successfully run TryRemoteBrowser() on
    * this object, which means you can't have called ShowRemoteFrame() or
    * ReallyStartLoading().
    */
   void SetRemoteBrowser(nsITabParent* aTabParent);
 
+  /**
+   * Stashes a detached view on the frame loader. We do this when we're
+   * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
+   * being reframed we'll restore the detached view when it's recreated,
+   * otherwise we'll discard the old presentation and set the detached
+   * subdoc view to null. aContainerDoc is the document containing the
+   * the subdoc frame. This enables us to detect when the containing
+   * document has changed during reframe, so we can discard the presentation 
+   * in that case.
+   */
+  void SetDetachedSubdocView(nsIView* aDetachedView,
+                             nsIDocument* aContainerDoc);
+
+  /**
+   * Retrieves the detached view and the document containing the view,
+   * as set by SetDetachedSubdocView().
+   */
+  nsIView* GetDetachedSubdocView(nsIDocument** aContainerDoc) const;
+
 private:
 
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
   bool ShouldUseRemoteProcess();
 
   /**
    * Is this a frameloader for a bona fide <iframe mozbrowser> or
@@ -321,16 +340,26 @@ private:
   nsCOMPtr<nsIDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURIToLoad;
   mozilla::dom::Element* mOwnerContent; // WEAK
 public:
   // public because a callback needs these.
   nsRefPtr<nsFrameMessageManager> mMessageManager;
   nsCOMPtr<nsIInProcessContentFrameMessageManager> mChildMessageManager;
 private:
+  // Stores the root view of the subdocument while the subdocument is being
+  // reframed. Used to restore the presentation after reframing.
+  nsIView* mDetachedSubdocViews;
+  // Stores the containing document of the frame corresponding to this
+  // frame loader. This is reference is kept valid while the subframe's
+  // presentation is detached and stored in mDetachedSubdocViews. This
+  // enables us to detect whether the frame has moved documents during
+  // a reframe, so that we know not to restore the presentation.
+  nsCOMPtr<nsIDocument> mContainerDocWhileDetached;
+
   bool mDepthTooGreat : 1;
   bool mIsTopLevelContent : 1;
   bool mDestroyCalled : 1;
   bool mNeedsAsyncDestroy : 1;
   bool mInSwap : 1;
   bool mInShow : 1;
   bool mHideCalled : 1;
   // True when the object is created for an element which the parser has
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -602,68 +602,58 @@ nsGenericElement::GetScrollFrame(nsIFram
 
   return nullptr;
 }
 
 PRInt32
 nsGenericElement::GetScrollTop()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
-
-  return sf ?
-         nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().y) :
-         0;
+  return sf ? sf->GetScrollPositionCSSPixels().y : 0;
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollTop(PRInt32* aScrollTop)
 {
   *aScrollTop = GetScrollTop();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
-    nsPoint pt = sf->GetScrollPosition();
-    sf->ScrollToCSSPixels(nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
-                                     aScrollTop));
+    sf->ScrollToCSSPixels(nsIntPoint(sf->GetScrollPositionCSSPixels().x, aScrollTop));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollLeft()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
-
-  return sf ?
-         nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().x) :
-         0;
+  return sf ? sf->GetScrollPositionCSSPixels().x : 0;
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollLeft(PRInt32* aScrollLeft)
 {
   *aScrollLeft = GetScrollLeft();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
-    nsPoint pt = sf->GetScrollPosition();
-    sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft,
-                                     nsPresContext::AppUnitsToIntCSSPixels(pt.y)));
+    sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft, sf->GetScrollPositionCSSPixels().y));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollHeight()
 {
   if (IsSVG())
@@ -2805,17 +2795,17 @@ nsGenericElement::MozRequestPointerLock(
   OwnerDoc()->RequestPointerLock(this);
   return NS_OK;
 }
 
 static const char*
 GetFullScreenError(nsIDocument* aDoc)
 {
   nsCOMPtr<nsPIDOMWindow> win = aDoc->GetWindow();
-  if (win && win->IsInAppOrigin()) {
+  if (aDoc->NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED) {
     // Request is in a web app and in the same origin as the web app.
     // Don't enforce as strict security checks for web apps, the user
     // is supposed to have trust in them. However documents cross-origin
     // to the web app must still confirm to the normal security checks.
     return nullptr;
   }
 
   if (!nsContentUtils::IsRequestFullScreenAllowed()) {
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -47,16 +47,17 @@ CPPSRCS += \
 	WebGLContextUtils.cpp \
 	WebGLContextReporter.cpp \
 	WebGLContextValidate.cpp \
 	WebGLExtensionStandardDerivatives.cpp \
 	WebGLExtensionTextureFilterAnisotropic.cpp \
 	WebGLExtensionLoseContext.cpp \
 	WebGLTexelConversions.cpp \
 	WebGLExtensionCompressedTextureS3TC.cpp \
+	WebGLExtensionDepthTexture.cpp \
 	$(NULL)
 
 DEFINES += -DUSE_ANGLE
 USE_ANGLE=1
 
 else
 
 CPPSRCS += WebGLContextNotSupported.cpp
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -663,18 +663,18 @@ void WebGLContext::LoseOldestWebGLContex
     }
 
     // note that here by "context" we mean "non-lost context". See the check for
     // IsContextLost() below. Indeed, the point of this function is to maybe lose
     // some currently non-lost context.
 
     uint64_t oldestIndex = UINT64_MAX;
     uint64_t oldestIndexThisPrincipal = UINT64_MAX;
-    const WebGLContext *oldestContext = nsnull;
-    const WebGLContext *oldestContextThisPrincipal = nsnull;
+    const WebGLContext *oldestContext = nullptr;
+    const WebGLContext *oldestContextThisPrincipal = nullptr;
     size_t numContexts = 0;
     size_t numContextsThisPrincipal = 0;
 
     for(size_t i = 0; i < contexts.Length(); ++i) {
 
         // don't want to lose ourselves.
         if (contexts[i] == this)
             continue;
@@ -1002,16 +1002,28 @@ bool WebGLContext::IsExtensionSupported(
                 isSupported = true;
             } else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) &&
                        gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt3) &&
                        gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt5))
             {
                 isSupported = true;
             }
             break;
+        case WEBGL_depth_texture:
+            if (gl->IsGLES2() && 
+                gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil) &&
+                gl->IsExtensionSupported(GLContext::OES_depth_texture)) 
+            {
+                isSupported = true;
+            } else if (!gl->IsGLES2() &&
+                       gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil)) 
+            {
+                isSupported = true;
+            }
+            break;
         default:
             MOZ_ASSERT(false, "should not get there.");
     }
 
     return isSupported;
 }
 
 NS_IMETHODIMP
@@ -1067,16 +1079,22 @@ WebGLContext::GetExtension(const nsAStri
             ext = WEBGL_lose_context;
     }
     else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"),
              nsCaseInsensitiveStringComparator()))
     {
         if (IsExtensionSupported(WEBGL_compressed_texture_s3tc))
             ext = WEBGL_compressed_texture_s3tc;
     }
+    else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"),
+             nsCaseInsensitiveStringComparator()))
+    {
+        if (IsExtensionSupported(WEBGL_depth_texture))
+            ext = WEBGL_depth_texture;
+    }
 
     if (ext == WebGLExtensionID_unknown_extension) {
       return nullptr;
     }
 
     if (!mExtensions[ext]) {
         switch (ext) {
             case OES_standard_derivatives:
@@ -1086,16 +1104,19 @@ WebGLContext::GetExtension(const nsAStri
                 mExtensions[ext] = new WebGLExtensionTextureFilterAnisotropic(this);
                 break;
             case WEBGL_lose_context:
                 mExtensions[ext] = new WebGLExtensionLoseContext(this);
                 break;
             case WEBGL_compressed_texture_s3tc:
                 mExtensions[ext] = new WebGLExtensionCompressedTextureS3TC(this);
                 break;
+            case WEBGL_depth_texture:
+                mExtensions[ext] = new WebGLExtensionDepthTexture(this);
+                break;
             default:
                 // create a generic WebGLExtension object for any extensions that don't
                 // have any additional tokens or methods. We still need these to be separate
                 // objects in case the user might extend the corresponding JS objects with custom
                 // properties.
                 mExtensions[ext] = new WebGLExtension(this);
                 break;
         }
@@ -1662,16 +1683,18 @@ WebGLContext::GetSupportedExtensions(Nul
     if (IsExtensionSupported(EXT_texture_filter_anisotropic)) {
         arr.AppendElement(NS_LITERAL_STRING("EXT_texture_filter_anisotropic"));
         arr.AppendElement(NS_LITERAL_STRING("MOZ_EXT_texture_filter_anisotropic"));
     }
     if (IsExtensionSupported(WEBGL_lose_context))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
     if (IsExtensionSupported(WEBGL_compressed_texture_s3tc))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
+    if (IsExtensionSupported(WEBGL_depth_texture))
+        arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"));
 }
 
 NS_IMETHODIMP
 WebGLContext::IsContextLost(WebGLboolean *retval)
 {
     *retval = mContextStatus != ContextStable;
     return NS_OK;
 }
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -106,21 +106,24 @@ enum WebGLTexelFormat
     BadFormat,
     // dummy pseudo-format meaning "use the other format".
     // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
     // is implicitly treated as being RGB8 itself.
     Auto,
     // 1-channel formats
     R8,
     A8,
+    D16, // used for WEBGL_depth_texture extension
+    D32, // used for WEBGL_depth_texture extension
     R32F, // used for OES_texture_float extension
     A32F, // used for OES_texture_float extension
     // 2-channel formats
     RA8,
     RA32F,
+    D24S8, // used for WEBGL_depth_texture extension
     // 3-channel formats
     RGB8,
     BGRX8, // used for DOM elements. Source format only.
     RGB565,
     RGB32F, // used for OES_texture_float extension
     // 4-channel formats
     RGBA8,
     BGRA8, // used for DOM elements
@@ -456,16 +459,17 @@ class WebGLContext :
     public WebGLRectangleObject,
     public nsWrapperCache
 {
     friend class WebGLMemoryMultiReporterWrapper;
     friend class WebGLExtensionLoseContext;
     friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLContextUserData;
     friend class WebGLMemoryPressureObserver;
+    friend class WebGLExtensionDepthTexture;
 
 public:
     WebGLContext();
     virtual ~WebGLContext();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext,
@@ -1142,16 +1146,17 @@ protected:
 
     // extensions
     enum WebGLExtensionID {
         OES_texture_float,
         OES_standard_derivatives,
         EXT_texture_filter_anisotropic,
         WEBGL_lose_context,
         WEBGL_compressed_texture_s3tc,
+        WEBGL_depth_texture,
         WebGLExtensionID_number_of_extensions,
         WebGLExtensionID_unknown_extension
     };
     nsAutoTArray<nsRefPtr<WebGLExtension>, WebGLExtensionID_number_of_extensions> mExtensions;
 
     // returns true if the extension has been enabled by calling getExtension.
     bool IsExtensionEnabled(WebGLExtensionID ext) {
         return mExtensions[ext];
@@ -2692,18 +2697,38 @@ public:
     bool IsComplete() const {
         const WebGLRectangleObject *thisRect = RectangleObject();
 
         if (!thisRect ||
             !thisRect->Width() ||
             !thisRect->Height())
             return false;
 
-        if (mTexturePtr)
-            return mAttachmentPoint == LOCAL_GL_COLOR_ATTACHMENT0;
+        if (mTexturePtr) {
+            if (!mTexturePtr->HasImageInfoAt(0, 0))
+                return false;
+
+            WebGLenum format = mTexturePtr->ImageInfoAt(0).Format();
+            switch (mAttachmentPoint)
+            {
+                case LOCAL_GL_COLOR_ATTACHMENT0:
+                    return format == LOCAL_GL_ALPHA ||
+                           format == LOCAL_GL_LUMINANCE ||
+                           format == LOCAL_GL_LUMINANCE_ALPHA ||
+                           format == LOCAL_GL_RGB ||
+                           format == LOCAL_GL_RGBA;
+                case LOCAL_GL_DEPTH_ATTACHMENT:
+                    return format == LOCAL_GL_DEPTH_COMPONENT;
+                case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
+                    return format == LOCAL_GL_DEPTH_STENCIL;
+
+                default:
+                    MOZ_NOT_REACHED("Invalid WebGL texture format?");
+            }
+        } 
 
         if (mRenderbufferPtr) {
             WebGLenum format = mRenderbufferPtr->InternalFormat();
             switch (mAttachmentPoint) {
                 case LOCAL_GL_COLOR_ATTACHMENT0:
                     return format == LOCAL_GL_RGB565 ||
                            format == LOCAL_GL_RGB5_A1 ||
                            format == LOCAL_GL_RGBA4;
@@ -2939,16 +2964,19 @@ public:
     NS_DECL_NSIWEBGLFRAMEBUFFER
 
     bool CheckAndInitializeRenderbuffers()
     {
         // enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not
         // generate the INVALID_FRAMEBUFFER_OPERATION that we need here
         if (HasDepthStencilConflict())
             return false;
+        
+        if (HasIncompleteAttachment())
+            return false;
 
         if (!mColorAttachment.HasUninitializedRenderbuffer() &&
             !mDepthAttachment.HasUninitializedRenderbuffer() &&
             !mStencilAttachment.HasUninitializedRenderbuffer() &&
             !mDepthStencilAttachment.HasUninitializedRenderbuffer())
             return true;
 
         // ensure INVALID_FRAMEBUFFER_OPERATION in zero-size case
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -1032,16 +1032,20 @@ WebGLContext::CopyTexImage2D(WebGLenum t
                                     internalformat == LOCAL_GL_ALPHA ||
                                     internalformat == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
                                                  : bool(gl->ActualFormat().alpha > 0);
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT ||
+        internalformat == LOCAL_GL_DEPTH_STENCIL)
+        return ErrorInvalidOperation("copyTexImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+
     if (mBoundFramebuffer)
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
 
     WebGLTexture *tex = activeBoundTextureForTarget(target);
     if (!tex)
         return ErrorInvalidOperation("copyTexImage2D: no texture bound to this target");
 
@@ -1153,16 +1157,20 @@ WebGLContext::CopyTexSubImage2D(WebGLenu
                                   format == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment().HasAlpha()
                                                  : bool(gl->ActualFormat().alpha > 0);
 
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
+    if (format == LOCAL_GL_DEPTH_COMPONENT ||
+        format == LOCAL_GL_DEPTH_STENCIL)
+        return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+
     if (mBoundFramebuffer)
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
 
     return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
 }
 
 
@@ -2125,16 +2133,22 @@ WebGLContext::GenerateMipmap(WebGLenum t
 
     if (!tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
     GLenum format = tex->ImageInfoAt(0, 0).Format();
     if (IsTextureFormatCompressed(format))
         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
 
+    if (IsExtensionEnabled(WEBGL_depth_texture) && 
+        (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL))
+        return ErrorInvalidOperation("generateMipmap: "
+                                     "A texture that has a base internal format of "
+                                     "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+
     if (!tex->AreAllLevel0ImageInfosEqual())
         return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
 
     tex->SetGeneratedMipmap();
 
     MakeContextCurrent();
 
     if (gl->WorkAroundDriverBugs()) {
@@ -5611,16 +5625,18 @@ WebGLContext::TexImage2D_base(WebGLenum 
     }
 
     switch (format) {
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
         case LOCAL_GL_ALPHA:
         case LOCAL_GL_LUMINANCE:
         case LOCAL_GL_LUMINANCE_ALPHA:
+        case LOCAL_GL_DEPTH_COMPONENT:
+        case LOCAL_GL_DEPTH_STENCIL:
             break;
         default:
             return ErrorInvalidEnumInfo("texImage2D: internal format", internalformat);
     }
 
     if (format != internalformat)
         return ErrorInvalidOperation("texImage2D: format does not match internalformat");
 
@@ -5632,16 +5648,30 @@ WebGLContext::TexImage2D_base(WebGLenum 
         if (!(is_pot_assuming_nonnegative(width) &&
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texImage2D: with level > 0, width and height must be powers of two");
     }
 
     if (border != 0)
         return ErrorInvalidValue("texImage2D: border must be 0");
 
+
+    if (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL) {
+        if (IsExtensionEnabled(WEBGL_depth_texture)) {
+            if (target != LOCAL_GL_TEXTURE_2D || data != NULL || level != 0)
+                return ErrorInvalidOperation("texImage2D: "
+                                             "with format of DEPTH_COMPONENT or DEPTH_STENCIL "
+                                             "target must be TEXTURE_2D, "
+                                             "data must be NULL, "
+                                             "level must be zero");
+        }
+        else
+            return ErrorInvalidEnumInfo("texImage2D: internal format", internalformat);
+    }
+
     uint32_t dstTexelSize = 0;
     if (!ValidateTexFormatAndType(format, type, jsArrayType, &dstTexelSize, "texImage2D"))
         return;
 
     WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
 
     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
@@ -5844,16 +5874,21 @@ WebGLContext::TexSubImage2D_base(WebGLen
     }
 
     if (level >= 1) {
         if (!(is_pot_assuming_nonnegative(width) &&
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texSubImage2D: with level > 0, width and height must be powers of two");
     }
 
+    if (IsExtensionEnabled(WEBGL_depth_texture) && 
+        (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL)) {
+        return ErrorInvalidOperation("texSubImage2D: format");
+    }
+
     uint32_t dstTexelSize = 0;
     if (!ValidateTexFormatAndType(format, type, jsArrayType, &dstTexelSize, "texSubImage2D"))
         return;
 
     WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
 
     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
@@ -6112,16 +6147,40 @@ BaseTypeAndSizeFromUniformType(WebGLenum
     }
 
     return true;
 }
 
 
 WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
 {
+    //
+    // WEBGL_depth_texture
+    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+        switch (type) {
+            case LOCAL_GL_UNSIGNED_SHORT:
+                return WebGLTexelConversions::D16;
+            case LOCAL_GL_UNSIGNED_INT:
+                return WebGLTexelConversions::D32;
+            default:
+                MOZ_NOT_REACHED("Invalid WebGL texture format/type?");
+                return WebGLTexelConversions::BadFormat;
+        }
+    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+        switch (type) {
+            case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
+                return WebGLTexelConversions::D24S8;
+            default:
+                MOZ_NOT_REACHED("Invalid WebGL texture format/type?");
+                NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
+                return WebGLTexelConversions::BadFormat;
+        }
+    }
+
+
     if (type == LOCAL_GL_UNSIGNED_BYTE) {
         switch (format) {
             case LOCAL_GL_RGBA:
                 return WebGLTexelConversions::RGBA8;
             case LOCAL_GL_RGB:
                 return WebGLTexelConversions::RGB8;
             case LOCAL_GL_ALPHA:
                 return WebGLTexelConversions::A8;
@@ -6169,16 +6228,28 @@ WebGLenum
 InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2)
 {
     // ES2 requires that format == internalformat; floating-point is
     // indicated purely by the type that's loaded.  For desktop GL, we
     // have to specify a floating point internal format.
     if (isGLES2)
         return format;
 
+    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+        if (type == LOCAL_GL_UNSIGNED_SHORT)
+            return LOCAL_GL_DEPTH_COMPONENT16;
+        else if (type == LOCAL_GL_UNSIGNED_INT)
+            return LOCAL_GL_DEPTH_COMPONENT32;
+    } 
+    
+    if (format == LOCAL_GL_DEPTH_STENCIL) {
+        if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
+            return LOCAL_GL_DEPTH24_STENCIL8;
+    }
+
     switch (type) {
     case LOCAL_GL_UNSIGNED_BYTE:
     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
         return format;
 
     case LOCAL_GL_FLOAT:
--- a/content/canvas/src/WebGLContextNotSupported.cpp
+++ b/content/canvas/src/WebGLContextNotSupported.cpp
@@ -20,8 +20,9 @@ DOMCI_DATA(WebGLRenderbuffer, void)
 DOMCI_DATA(WebGLUniformLocation, void)
 DOMCI_DATA(WebGLShaderPrecisionFormat, void)
 DOMCI_DATA(WebGLActiveInfo, void)
 DOMCI_DATA(WebGLExtension, void)
 DOMCI_DATA(WebGLExtensionStandardDerivatives, void)
 DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, void)
 DOMCI_DATA(WebGLExtensionLoseContext, void)
 DOMCI_DATA(WebGLExtensionCompressedTextureS3TC, void)
+DOMCI_DATA(WebGLExtensionDepthTexture, void)
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -185,16 +185,18 @@ bool
 WebGLContext::IsTextureFormatCompressed(GLenum format)
 {
     switch(format) {
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
         case LOCAL_GL_ALPHA:
         case LOCAL_GL_LUMINANCE:
         case LOCAL_GL_LUMINANCE_ALPHA:
+        case LOCAL_GL_DEPTH_COMPONENT:
+        case LOCAL_GL_DEPTH_STENCIL:
             return false;
 
         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
             return true;
     }
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -451,16 +451,26 @@ bool WebGLContext::ValidateLevelWidthHei
 
 uint32_t WebGLContext::GetBitsPerTexel(WebGLenum format, WebGLenum type)
 {
     // If there is no defined format or type, we're not taking up any memory
     if (!format || !type) {
         return 0;
     }
 
+    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+        if (type == LOCAL_GL_UNSIGNED_SHORT)
+            return 2;
+        else if (type == LOCAL_GL_UNSIGNED_INT)
+            return 4;
+    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+        if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
+            return 4;
+    }
+
     if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
         int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
         switch (format) {
             case LOCAL_GL_ALPHA:
             case LOCAL_GL_LUMINANCE:
                 return 1 * multiplier;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return 2 * multiplier;
@@ -486,16 +496,58 @@ uint32_t WebGLContext::GetBitsPerTexel(W
 
     NS_ABORT();
     return 0;
 }
 
 bool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
                                               uint32_t *texelSize, const char *info)
 {
+    if (IsExtensionEnabled(WEBGL_depth_texture)) {
+        if (format == LOCAL_GL_DEPTH_COMPONENT) {
+            if (jsArrayType != -1) {
+                if ((type == LOCAL_GL_UNSIGNED_SHORT && jsArrayType != js::ArrayBufferView::TYPE_UINT16) ||
+                    (type == LOCAL_GL_UNSIGNED_INT && jsArrayType != js::ArrayBufferView::TYPE_UINT32)) {
+                    ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
+                    return false;
+                }
+            }
+
+            switch(type) {
+                case LOCAL_GL_UNSIGNED_SHORT:
+                    *texelSize = 2;
+                    break;
+                case LOCAL_GL_UNSIGNED_INT:
+                    *texelSize = 4;
+                    break;
+                default:
+                    ErrorInvalidOperation("%s: invalid type 0x%x", info, type);
+                    return false;
+            }
+
+            return true;
+
+        } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+            if (type != LOCAL_GL_UNSIGNED_INT_24_8_EXT) {
+                ErrorInvalidOperation("%s: invalid format 0x%x", info, format);
+                return false;
+            }
+            if (jsArrayType != -1) {
+                if (jsArrayType != js::ArrayBufferView::TYPE_UINT32) {
+                    ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
+                    return false;
+                }
+            }
+
+            *texelSize = 4;
+            return true;
+        }
+    }
+
+
     if (type == LOCAL_GL_UNSIGNED_BYTE ||
         (IsExtensionEnabled(OES_texture_float) && type == LOCAL_GL_FLOAT))
     {
         if (jsArrayType != -1) {
             if ((type == LOCAL_GL_UNSIGNED_BYTE && jsArrayType != js::ArrayBufferView::TYPE_UINT8) ||
                 (type == LOCAL_GL_FLOAT && jsArrayType != js::ArrayBufferView::TYPE_FLOAT32))
             {
                 ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLExtensionDepthTexture.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "WebGLContext.h"
+#include "WebGLExtensions.h"
+
+using namespace mozilla;
+
+WebGLExtensionDepthTexture::WebGLExtensionDepthTexture(WebGLContext* context) :
+    WebGLExtension(context)
+{
+
+}
+
+WebGLExtensionDepthTexture::~WebGLExtensionDepthTexture()
+{
+
+}
+
+NS_IMPL_ADDREF_INHERITED(WebGLExtensionDepthTexture, WebGLExtension)
+NS_IMPL_RELEASE_INHERITED(WebGLExtensionDepthTexture, WebGLExtension)
+
+DOMCI_DATA(WebGLExtensionDepthTexture, WebGLExtensionDepthTexture)
+
+NS_INTERFACE_MAP_BEGIN(WebGLExtensionDepthTexture)
+  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionDepthTexture)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionDepthTexture)
+NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+
--- a/content/canvas/src/WebGLExtensions.h
+++ b/content/canvas/src/WebGLExtensions.h
@@ -51,11 +51,23 @@ class WebGLExtensionCompressedTextureS3T
 public:
     WebGLExtensionCompressedTextureS3TC(WebGLContext* context);
     virtual ~WebGLExtensionCompressedTextureS3TC();
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBGLEXTENSION
 };
 
+class WebGLExtensionDepthTexture :
+    public nsIWebGLExtensionDepthTexture,
+    public WebGLExtension
+{
+public:
+    WebGLExtensionDepthTexture(WebGLContext* context);
+    virtual ~WebGLExtensionDepthTexture();
+
+    NS_DECL_ISUPPORTS_INHERITED
+    NS_DECL_NSIWEBGLEXTENSION
+};
+
 }
 
 #endif // WEBGLEXTENSIONS_H_
--- a/content/canvas/src/WebGLTexelConversions.h
+++ b/content/canvas/src/WebGLTexelConversions.h
@@ -104,24 +104,27 @@ inline size_t TexelBytesForFormat(int fo
     switch (format) {
         case WebGLTexelConversions::R8:
         case WebGLTexelConversions::A8:
             return 1;
         case WebGLTexelConversions::RA8:
         case WebGLTexelConversions::RGBA5551:
         case WebGLTexelConversions::RGBA4444:
         case WebGLTexelConversions::RGB565:
+        case WebGLTexelConversions::D16:
             return 2;
         case WebGLTexelConversions::RGB8:
             return 3;
         case WebGLTexelConversions::RGBA8:
         case WebGLTexelConversions::BGRA8:
         case WebGLTexelConversions::BGRX8:
         case WebGLTexelConversions::R32F:
         case WebGLTexelConversions::A32F:
+        case WebGLTexelConversions::D32:
+        case WebGLTexelConversions::D24S8:
             return 4;
         case WebGLTexelConversions::RA32F:
             return 8;
         case WebGLTexelConversions::RGB32F:
             return 12;
         case WebGLTexelConversions::RGBA32F:
             return 16;
         default:
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -4640,33 +4640,30 @@ nsCanvasRenderingContext2DAzure::GetCanv
   }
 
   nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
   if (!canvasLayer) {
     NS_WARNING("CreateCanvasLayer returned null!");
     return nullptr;
   }
   CanvasRenderingContext2DUserDataAzure *userData = nullptr;
-  if (aBuilder->IsPaintingToWindow()) {
-    // Make the layer tell us whenever a transaction finishes (including
-    // the current transaction), so we can clear our invalidation state and
-    // start invalidating again. We need to do this for the layer that is
-    // being painted to a window (there shouldn't be more than one at a time,
-    // and if there is, flushing the invalidation state more often than
-    // necessary is harmless).
-
-    // The layer will be destroyed when we tear down the presentation
-    // (at the latest), at which time this userData will be destroyed,
-    // releasing the reference to the element.
-    // The userData will receive DidTransactionCallbacks, which flush the
-    // the invalidation state to indicate that the canvas is up to date.
-    userData = new CanvasRenderingContext2DUserDataAzure(this);
-    canvasLayer->SetDidTransactionCallback(
-            CanvasRenderingContext2DUserDataAzure::DidTransactionCallback, userData);
-  }
+  // Make the layer tell us whenever a transaction finishes (including
+  // the current transaction), so we can clear our invalidation state and
+  // start invalidating again. We need to do this for all layers since
+  // callers of DrawWindow may be expecting to receive normal invalidation
+  // notifications after this paint.
+
+  // The layer will be destroyed when we tear down the presentation
+  // (at the latest), at which time this userData will be destroyed,
+  // releasing the reference to the element.
+  // The userData will receive DidTransactionCallbacks, which flush the
+  // the invalidation state to indicate that the canvas is up to date.
+  userData = new CanvasRenderingContext2DUserDataAzure(this);
+  canvasLayer->SetDidTransactionCallback(
+          CanvasRenderingContext2DUserDataAzure::DidTransactionCallback, userData);
   canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
 
   CanvasLayer::Data data;
 
   data.mDrawTarget = mTarget;
   data.mSize = nsIntSize(mWidth, mHeight);
 
   canvasLayer->Initialize(data);
--- a/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
+++ b/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
@@ -1,8 +1,9 @@
 oes-standard-derivatives.html
 ext-texture-filter-anisotropic.html
 oes-texture-float.html
 oes-vertex-array-object.html
 webgl-debug-renderer-info.html
 webgl-debug-shaders.html
 --min-version 1.0.2 webgl-compressed-texture-s3tc.html
+--min-version 1.0.2 webgl-depth-texture.html
 
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/conformance/extensions/webgl-depth-texture.html
@@ -0,0 +1,343 @@
+<!--
+
+/*
+** Copyright (c) 2012 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
+<script src="../../resources/js-test-pre.js"></script>
+<script src="../resources/webgl-test.js"></script>
+<script src="../resources/webgl-test-utils.js"></script>
+<title>WebGL WEBGL_depth_texture Conformance Tests</title>
+</head>
+<body>
+<script id="vshader" type="x-shader/x-vertex">
+attribute vec4 a_position;
+void main()
+{
+    gl_Position = a_position;
+}
+</script>
+
+<script id="fshader" type="x-shader/x-fragment">
+precision mediump float;
+uniform sampler2D u_texture;
+uniform vec2 u_resolution;
+void main()
+{
+    vec2 texcoord = gl_FragCoord.xy / u_resolution;
+    gl_FragColor = texture2D(u_texture, texcoord);
+}
+</script>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<script>
+if (window.initNonKhronosFramework) {
+    window.initNonKhronosFramework(false);
+}
+description("This test verifies the functionality of the WEBGL_depth_texture extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var ext = null;
+var vao = null;
+var tex;
+var name;
+var supportedFormats;
+
+if (!gl) {
+    testFailed("WebGL context does not exist");
+} else {
+    testPassed("WebGL context exists");
+
+    // Run tests with extension disabled
+    runTestDisabled();
+
+    // Query the extension and store globally so shouldBe can access it
+    ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
+    if (!ext) {
+        testPassed("No WEBGL_depth_texture support -- this is legal");
+        runSupportedTest(false);
+    } else {
+        testPassed("Successfully enabled WEBGL_depth_texture extension");
+
+        runSupportedTest(true);
+        runTestExtension();
+    }
+}
+
+function runSupportedTest(extensionEnabled) {
+    var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
+    if (name !== undefined) {
+        if (extensionEnabled) {
+            testPassed("WEBGL_depth_texture listed as supported and getExtension succeeded");
+        } else {
+            testFailed("WEBGL_depth_texture listed as supported but getExtension failed");
+        }
+    } else {
+        if (extensionEnabled) {
+            testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded");
+        } else {
+            testPassed("WEBGL_depth_texture not listed as supported and getExtension failed -- this is legal");
+        }
+    }
+}
+
+
+function runTestDisabled() {
+    debug("Testing binding enum with extension disabled");
+
+    var tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+    shouldGenerateGLError(gl, gl.INVALID_ENUM, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)');
+    shouldGenerateGLError(gl, gl.INVALID_ENUM, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)');
+}
+
+
+function dumpIt(gl, res, msg) {
+  return;  // comment out to debug
+  debug(msg);
+  var actualPixels = new Uint8Array(res * res * 4);
+  gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
+
+  for (var yy = 0; yy < res; ++yy) {
+    var strs = [];
+    for (var xx = 0; xx < res; ++xx) {
+      var actual = (yy * res + xx) * 4;
+      strs.push("(" + actualPixels[actual] + "," + actualPixels[actual+1] + "," + actualPixels[actual + 2] + "," + actualPixels[actual + 3] + ")");
+    }
+    debug(strs.join(" "));
+  }
+}
+function runTestExtension() {
+    debug("Testing WEBGL_depth_texture");
+
+    var res = 8;
+
+    // make canvas for testing.
+    canvas2 = document.createElement("canvas");
+    canvas2.width = res;
+    canvas2.height = res;
+    var ctx = canvas2.getContext("2d");
+    ctx.fillStyle = "blue";
+    ctx.fillRect(0, 0, canvas2.width, canvas2.height);
+
+    var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']);
+    gl.useProgram(program);
+    gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), res, res);
+
+    var buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+    gl.bufferData(
+        gl.ARRAY_BUFFER,
+        new Float32Array(
+            [   1,  1,  1,
+               -1,  1,  0,
+               -1, -1, -1,
+                1,  1,  1,
+               -1, -1, -1,
+                1, -1,  0,
+            ]),
+        gl.STATIC_DRAW);
+    gl.enableVertexAttribArray(0);
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+    var types = [
+        {obj: 'gl',  attachment: 'DEPTH_ATTACHMENT',         format: 'DEPTH_COMPONENT', type: 'UNSIGNED_SHORT',          data: 'new Uint16Array(1)' },
+        {obj: 'gl',  attachment: 'DEPTH_ATTACHMENT',         format: 'DEPTH_COMPONENT', type: 'UNSIGNED_INT',            data: 'new Uint32Array(1)' },
+        {obj: 'ext', attachment: 'DEPTH_STENCIL_ATTACHMENT', format: 'DEPTH_STENCIL',   type: 'UNSIGNED_INT_24_8_WEBGL', data: 'new Uint32Array(1)' }
+    ];
+
+    for (var ii = 0; ii < types.length; ++ii) {
+        var typeInfo = types[ii];
+        var type = typeInfo.type;
+        var typeStr = typeInfo.obj + '.' + type;
+
+        debug("");
+        debug("testing: " + type);
+
+        // check that cubemaps are not allowed.
+        var cubeTex = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTex);
+        var targets = [
+          'TEXTURE_CUBE_MAP_POSITIVE_X',
+          'TEXTURE_CUBE_MAP_NEGATIVE_X',
+          'TEXTURE_CUBE_MAP_POSITIVE_Y',
+          'TEXTURE_CUBE_MAP_NEGATIVE_Y',
+          'TEXTURE_CUBE_MAP_POSITIVE_Z',
+          'TEXTURE_CUBE_MAP_NEGATIVE_Z'
+        ];
+        for (var tt = 0; tt < targets.length; ++tt) {
+            shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.' + targets[ii] + ', 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+        }
+
+        // check 2d textures.
+        tex = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, tex);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+
+        // test level > 0
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+
+        // test with data
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')');
+
+        // test with canvas
+        shouldGenerateGLError(gl, [gl.INVALID_VALUE, gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', gl.' + typeInfo.format + ', ' + typeStr  + ', canvas2)');
+
+        // test copyTexImage2D
+        shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 0, 0, 1, 1, 0)');
+
+        // test real thing
+        shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', ' + res + ', ' + res + ', 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
+
+        // test texSubImage2D
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.' + typeInfo.format + ', ' + typeStr  + ', ' + typeInfo.data + ')');
+
+        // test copyTexSubImage2D
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1)');
+
+        // test generateMipmap
+        shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.generateMipmap(gl.TEXTURE_2D)');
+
+        var fbo = gl.createFramebuffer();
+        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, tex, 0);
+        // TODO: remove this check if the spec is updated to require these combinations to work.
+        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
+        {
+            // try adding a color buffer.
+            var colorTex = gl.createTexture();
+            gl.bindTexture(gl.TEXTURE_2D, colorTex);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, res, res, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);
+            shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+        }
+
+        // use the default texture to render with while we return to the depth texture.
+        gl.bindTexture(gl.TEXTURE_2D, null);
+
+        // render the z-quad
+        gl.enable(gl.DEPTH_TEST);
+        gl.clearColor(1, 0, 0, 1);
+        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+        dumpIt(gl, res, "--first--");
+
+        // render the depth texture.
+        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+        gl.bindTexture(gl.TEXTURE_2D, tex);
+        gl.clearColor(0, 0, 1, 1);
+        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+        gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+        var actualPixels = new Uint8Array(res * res * 4);
+        gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
+
+        dumpIt(gl, res, "--depth--");
+
+        // Check that each pixel's RGB are the same and that it's value is less
+        // than the previous pixel in either direction. Basically verify we have a
+        // gradient.
+        var success = true;
+        for (var yy = 0; yy < res; ++yy) {
+          for (var xx = 0; xx < res; ++xx) {
+            var actual = (yy * res + xx) * 4;
+            var left = actual - 4;
+            var down = actual - res * 4;
+
+            if (actualPixels[actual + 0] != actualPixels[actual + 1]) {
+                testFailed('R != G');
+                success = false;
+            }
+            if (actualPixels[actual + 0] != actualPixels[actual + 2]) {
+                testFailed('R != B');
+                success = false;
+            }
+            // ALPHA is implementation dependent
+            if (actualPixels[actual + 3] != 0xFF && actualPixels[actual + 3] != actualPixels[actual + 0]) {
+                testFailed('A != 255 && A != R');
+                success = false;
+            }
+
+            if (xx > 0) {
+              if (actualPixels[actual] <= actualPixels[left]) {
+                  testFailed("actual(" + actualPixels[actual] + ") < left(" + actualPixels[left] + ")");
+                  success = false;
+              }
+            }
+            if (yy > 0) {
+                if (actualPixels[actual] <= actualPixels[down]) {
+                    testFailed("actual(" + actualPixels[actual] + ") < down(" + actualPixels[down] + ")");
+                    success = false;
+                }
+            }
+          }
+        }
+
+        // Check that bottom left corner is vastly different thatn top right.
+        if (actualPixels[(res * res - 1) * 4] - actualPixels[0] < 0xC0) {
+            testFailed("corners are not different enough");
+            success = false;
+        }
+
+        if (success) {
+            testPassed("depth texture rendered correctly.");
+        }
+
+        // check limitations
+        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, null, 0);
+        var badAttachment = typeInfo.attachment == 'DEPTH_ATTACHMENT' ? 'DEPTH_STENCIL_ATTACHMENT' : 'DEPTH_ATTACHMENT';
+        shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.' + badAttachment + ', gl.TEXTURE_2D, tex, 0)');
+        shouldNotBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+        shouldGenerateGLError(gl, gl.INVALID_FRAMEBUFFER_OPERATION, 'gl.clear(gl.DEPTH_BUFFER_BIT)');
+        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+        shouldBe('gl.getError()', 'gl.NO_ERROR');
+    }
+}
+
+debug("");
+successfullyParsed = true;
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
+
--- a/content/events/src/nsDOMTouchEvent.cpp
+++ b/content/events/src/nsDOMTouchEvent.cpp
@@ -158,17 +158,17 @@ nsDOMTouchList::GetLength(PRUint32* aLen
 {
   *aLength = mPoints.Length();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouchList::Item(PRUint32 aIndex, nsIDOMTouch** aRetVal)
 {
-  NS_IF_ADDREF(*aRetVal = mPoints.SafeElementAt(aIndex, nsnull));
+  NS_IF_ADDREF(*aRetVal = mPoints.SafeElementAt(aIndex, nullptr));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouchList::IdentifiedTouch(PRInt32 aIdentifier, nsIDOMTouch** aRetVal)
 {
   *aRetVal = nullptr;
   for (PRUint32 i = 0; i < mPoints.Length(); ++i) {
--- a/content/events/src/nsDOMTouchEvent.h
+++ b/content/events/src/nsDOMTouchEvent.h
@@ -109,17 +109,17 @@ public:
 
   void Append(nsIDOMTouch* aPoint)
   {
     mPoints.AppendElement(aPoint);
   }
 
   nsIDOMTouch* GetItemAt(PRUint32 aIndex)
   {
-    return mPoints.SafeElementAt(aIndex, nsnull);
+    return mPoints.SafeElementAt(aIndex, nullptr);
   }
 
 protected:
   nsTArray<nsCOMPtr<nsIDOMTouch> > mPoints;
 };
 
 class nsDOMTouchEvent : public nsDOMUIEvent,
                         public nsIDOMTouchEvent
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -864,14 +864,14 @@ nsEventDispatcher::CreateEvent(nsPresCon
     return NS_NewDOMTouchEvent(aDOMEvent, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("hashchangeevent"))
     return NS_NewDOMHashChangeEvent(aDOMEvent, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("customevent"))
     return NS_NewDOMCustomEvent(aDOMEvent, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("mozsmsevent"))
     return NS_NewDOMSmsEvent(aDOMEvent, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
-    return NS_NewDOMStorageEvent(aDOMEvent, aPresContext, nsnull);
+    return NS_NewDOMStorageEvent(aDOMEvent, aPresContext, nullptr);
   }
     
 
   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 }
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -327,17 +327,16 @@ public:
   static void EndTransaction();
   static void OnEvent(nsEvent* aEvent);
   static void Shutdown();
   static PRUint32 GetTimeoutTime();
 
 
   static DeltaValues AccelerateWheelDelta(widget::WheelEvent* aEvent,
                                           bool aAllowScrollSpeedOverride);
-  static bool IsAccelerationEnabled();
 
   enum {
     kScrollSeriesTimeout = 80
   };
 protected:
   static nsIntPoint GetScreenPoint(nsGUIEvent* aEvent);
   static void OnFailToScrollTarget();
   static void OnTimeout(nsITimer *aTimer, void *aClosure);
@@ -583,22 +582,16 @@ nsMouseWheelTransaction::GetTimeoutTime(
 }
 
 PRUint32
 nsMouseWheelTransaction::GetIgnoreMoveDelayTime()
 {
   return Preferences::GetUint("mousewheel.transaction.ignoremovedelay", 100);
 }
 
-bool
-nsMouseWheelTransaction::IsAccelerationEnabled()
-{
-  return GetAccelerationStart() >= 0 && GetAccelerationFactor() > 0;
-}
-
 DeltaValues
 nsMouseWheelTransaction::AccelerateWheelDelta(widget::WheelEvent* aEvent,
                                               bool aAllowScrollSpeedOverride)
 {
   DeltaValues result(aEvent);
 
   // Don't accelerate the delta values if the event isn't line scrolling.
   if (aEvent->deltaMode != nsIDOMWheelEvent::DOM_DELTA_LINE) {
@@ -2460,17 +2453,17 @@ nsEventStateManager::DoScrollHistory(PRI
 void
 nsEventStateManager::DoScrollZoom(nsIFrame *aTargetFrame,
                                   PRInt32 adjustment)
 {
   // Exclude form controls and XUL content.
   nsIContent *content = aTargetFrame->GetContent();
   if (content &&
       !content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
-      !content->IsXUL())
+      !content->OwnerDoc()->IsXUL())
     {
       // positive adjustment to decrease zoom, negative to increase
       PRInt32 change = (adjustment > 0) ? -1 : 1;
 
       if (Preferences::GetBool("browser.zoom.full") || content->GetCurrentDoc()->IsSyntheticDocument()) {
         ChangeFullZoom(change);
       } else {
         ChangeTextSize(change);
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -66,16 +66,18 @@ MOCHITEST_FILES = \
 		test_bug624127.html \
 		test_bug650493.html \
 		test_bug641477.html \
 		test_bug648573.html \
 		test_bug615597.html \
 		test_bug656379-1.html \
 		test_bug656379-2.html \
 		test_bug656954.html \
+		test_bug659071.html \
+		window_bug659071.html \
 		test_bug659350.html \
 		test_bug662678.html \
 		test_bug667919-1.html \
 		test_bug667919-2.html \
 		test_bug667612.html \
 		empty.js \
 		test_bug689564.html \
 		test_bug698929.html \
new file mode 100644
--- /dev/null
+++ b/content/events/test/test_bug659071.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=659071
+-->
+<head>
+  <title>Test for Bug 659071</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.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=659071">Mozilla Bug 659071</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 659071 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var subWin = window.open("window_bug659071.html", "_blank",
+                         "width=500,height=500");
+
+function finish()
+{
+  subWin.close();
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/events/test/window_bug659071.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 659071</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<video id="v" controls></video>
+<script type="application/javascript">
+
+SimpleTest.waitForFocus(runTests, window);
+
+function is()
+{
+  window.opener.is.apply(window.opener, arguments);
+}
+
+function isnot()
+{
+  window.opener.isnot.apply(window.opener, arguments);
+}
+
+function hitEventLoop(aFunc, aTimes)
+{
+  if (--aTimes) {
+    setTimeout(hitEventLoop, 0, aFunc, aTimes);
+  } else {
+    setTimeout(aFunc, 20);
+  }
+}
+
+function runTests()
+{
+  SpecialPowers.setIntPref("mousewheel.with_control.action", 3);
+  SpecialPowers.setFullZoom(window, 1.0);
+
+  var video = document.getElementById("v");
+  hitEventLoop(function () {
+    is(SpecialPowers.getFullZoom(window), 1.0,
+       "failed to reset zoom");
+    synthesizeWheel(video, 10, 10,
+      { deltaMode: WheelEvent.DOM_DELTA_LINE, ctrlKey: true,
+        deltaX: 0, deltaY: 1.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 });
+    hitEventLoop(function () {
+      isnot(SpecialPowers.getFullZoom(window), 1.0,
+             "failed to zoom by ctrl+wheel");
+
+      SpecialPowers.setFullZoom(window, 1.0);
+      SpecialPowers.clearUserPref("mousewheel.with_control.action");
+
+      hitEventLoop(window.opener.finish, 20);
+    }, 20);
+  }, 20);
+}
+
+</script>
+</body>
+</html>
\ No newline at end of file
--- a/content/html/content/test/forms/test_formnovalidate_attribute.html
+++ b/content/html/content/test/forms/test_formnovalidate_attribute.html
@@ -56,17 +56,16 @@ var observers = os.enumerateObservers("i
  * used to submit the form.
  *
  * The following test should not be done if there is no observer for
  * "invalidformsubmit" because the form submission will not be canceled in that
  * case.
  */
 
 if (observers.hasMoreElements()) {
-
   document.getElementById('av').addEventListener("invalid", function(aEvent) {
     aEvent.target.removeAttribute("invalid", arguments.callee, false);
     ok(true, "formnovalidate should not apply on if not set on the submit " +
              "control used for the submission");
     document.getElementById('b').click();
   }, false);
 
   document.getElementById('bv').addEventListener("invalid", function(aEvent) {
@@ -128,14 +127,16 @@ if (observers.hasMoreElements()) {
   document.forms[2].addEventListener("submit", unexpectedSubmit, false);
 
   SimpleTest.waitForExplicitFinish();
 
   // This is going to call all the tests (with a chain reaction).
   SimpleTest.waitForFocus(function() {
     document.getElementById('a').click();
   });
+} else {
+  todo(false, "No 'invalidformsubmit' observers. Skip test.");
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_bug605124-1.html
+++ b/content/html/content/test/test_bug605124-1.html
@@ -93,14 +93,16 @@ if (observers.hasMoreElements()) {
   checkPseudoClass(input, true);
   checkPseudoClass(select, true);
 
   // Remove the form.
   document.getElementsByTagName('table')[0].removeChild(form);
   checkPseudoClass(textarea, false);
   checkPseudoClass(input, false);
   checkPseudoClass(select, false);
+} else {
+  todo(false, "No 'invalidformsubmit' observers. Skip test.");
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_bug605125-1.html
+++ b/content/html/content/test/test_bug605125-1.html
@@ -99,14 +99,16 @@ if (observers.hasMoreElements()) {
   checkPseudoClass(input, true);
   checkPseudoClass(select, true);
 
   // Remove the form.
   document.getElementsByTagName('table')[0].removeChild(form);
   checkPseudoClass(textarea, false);
   checkPseudoClass(input, false);
   checkPseudoClass(select, false);
+} else {
+  todo(false, "No 'invalidformsubmit' observers. Skip test.");
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -22,17 +22,17 @@
 namespace mozilla {
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineDefaultVideoSource, nsITimerCallback)
 /**
  * Default video source.
  */
 
 MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource()
-  : mTimer(nsnull), mState(kReleased)
+  : mTimer(nullptr), mState(kReleased)
 {}
 
 MediaEngineDefaultVideoSource::~MediaEngineDefaultVideoSource()
 {}
 
 void
 MediaEngineDefaultVideoSource::GetName(nsAString& aName)
 {
--- a/docshell/base/SerializedLoadContext.h
+++ b/docshell/base/SerializedLoadContext.h
@@ -23,17 +23,17 @@ class nsIWebSocketChannel;
 
 namespace IPC {
 
 class SerializedLoadContext
 {
 public:
   SerializedLoadContext()
   {
-    Init(nsnull);
+    Init(nullptr);
   }
 
   SerializedLoadContext(nsILoadContext* aLoadContext);
   SerializedLoadContext(nsIChannel* aChannel);
   SerializedLoadContext(nsIWebSocketChannel* aChannel);
 
   void Init(nsILoadContext* aLoadContext);
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2841,28 +2841,53 @@ nsDocShell::CanAccessItem(nsIDocShellTre
 
     // For historical context, see:
     // 
     // Bug 13871:  Prevent frameset spoofing
     // Bug 103638: Targets with same name in different windows open in wrong
     //             window with javascript
     // Bug 408052: Adopt "ancestor" frame navigation policy
 
-    // Now do a security check
+    // Now do a security check.
+    //
+    // Disallow navigation if the two frames are not part of the same app, or if
+    // they have different is-in-browser-element states.
     //
     // Allow navigation if
     //  1) aAccessingItem can script aTargetItem or one of its ancestors in
     //     the frame hierarchy or
     //  2) aTargetItem is a top-level frame and aAccessingItem is its descendant
     //  3) aTargetItem is a top-level frame and aAccessingItem can target
     //     its opener per rule (1) or (2).
 
     if (aTargetItem == aAccessingItem) {
         // A frame is allowed to navigate itself.
-        return true;  
+        return true;
+    }
+
+    nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
+    nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
+    if (!!targetDS != !!accessingDS) {
+        // We must be able to convert both or neither to nsIDocShell.
+        return false;
+    }
+
+    if (targetDS && accessingDS) {
+        bool targetInBrowser = false, accessingInBrowser = false;
+        targetDS->GetIsInBrowserElement(&targetInBrowser);
+        accessingDS->GetIsInBrowserElement(&accessingInBrowser);
+
+        PRUint32 targetAppId = 0, accessingAppId = 0;
+        targetDS->GetAppId(&targetAppId);
+        accessingDS->GetAppId(&accessingAppId);
+
+        if (targetInBrowser != accessingInBrowser ||
+            targetAppId != accessingAppId) {
+            return false;
+        }
     }
 
     nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
     aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
 
     if (aTargetItem == accessingRoot) {
         // A frame can navigate its root.
         return true;
--- a/docshell/base/nsIContentViewer.idl
+++ b/docshell/base/nsIContentViewer.idl
@@ -22,17 +22,17 @@ class nsDOMNavigationTiming;
 [ptr] native nsIWidgetPtr(nsIWidget);
 [ptr] native nsIDocumentPtr(nsIDocument);
 [ref] native nsIntRectRef(nsIntRect);
 [ptr] native nsIPresShellPtr(nsIPresShell);
 [ptr] native nsPresContextPtr(nsPresContext);
 [ptr] native nsIViewPtr(nsIView);
 [ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming);
 
-[scriptable, builtinclass, uuid(26b2380b-4a1a-46cd-b7d8-7600e41c1688)]
+[scriptable, builtinclass, uuid(b9d92b8b-5623-4079-ae11-36bb341f322e)]
 interface nsIContentViewer : nsISupports
 {
 
   [noscript] void init(in nsIWidgetPtr aParentWidget,
                        [const] in nsIntRectRef aBounds);
 
   attribute nsISupports container;
 
@@ -129,37 +129,42 @@ interface nsIContentViewer : nsISupports
   void open(in nsISupports aState, in nsISHEntry aSHEntry);
 
   /**
    * Clears the current history entry.  This is used if we need to clear out
    * the saved presentation state.
    */
   void clearHistoryEntry();
 
-  /*
+  /**
    * Change the layout to view the document with page layout (like print preview), but
    * dynamic and editable (like Galley layout).
-  */
+   */
   void setPageMode(in boolean aPageMode, in nsIPrintSettings aPrintSettings);
 
   /**
    * Get the history entry that this viewer will save itself into when
    * destroyed.  Can return null
    */
   readonly attribute nsISHEntry historyEntry;
 
-  /*
+  /**
    * Indicates when we're in a state where content shouldn't be allowed to
    * trigger a tab-modal prompt (as opposed to a window-modal prompt) because
    * we're part way through some operation (eg beforeunload) that shouldn't be
    * rentrant if the user closes the tab while the prompt is showing.
    * See bug 613800.
    */
   readonly attribute boolean isTabModalPromptAllowed;
 
+  /**
+   * Returns whether this content viewer is in a hidden state.
+   */
+  readonly attribute boolean isHidden;
+
   [noscript] readonly attribute nsIPresShellPtr presShell;
   [noscript] readonly attribute nsPresContextPtr presContext;
   // aDocument must not be null.
   [noscript] void setDocumentInternal(in nsIDocumentPtr aDocument,
                                       in boolean aForceReuseInnerWindow);
   /**
    * Find the view to use as the container view for MakeWindow. Returns
    * null if this will be the root of a view manager hierarchy. In that
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -603,19 +603,32 @@ interface nsIDocShell : nsISupports
   readonly attribute boolean isContentBoundary;
 
   /**
    * Returns true iif the docshell is inside a browser element.
    */
   readonly attribute boolean isInBrowserElement;
 
   /**
-   * Returns true iif the docshell is inside an application.
-   * However, it will return false if the docshell is inside a browser element
-   * that is inside an application.
+   * Returns true iif the docshell is inside an application.  However, it will
+   * return false if the docshell is inside a browser element that is inside
+   * an application.
+   *
+   * Note: Do not use this method for permissions checks!  An app may contain
+   * an <iframe> pointing at arbitrary web code.  This iframe's docshell will
+   * have isInApp() == true, but the iframe's content is not "app code", and
+   * so should not be granted more trust than vanilla web content.
+   *
+   * (For example, suppose when web content calls API method X, we show a
+   * permission prompt, but when "app code" calls method X, we don't.  In this
+   * case, it would be /incorrect/ to show the permission prompt if
+   * !isInApp().)
+   *
+   * If you're doing a security check, use the content's principal instead of
+   * this method.
    */
   readonly attribute boolean isInApp;
 
   /**
    * Returns if the docshell has a docshell that behaves as a content boundary
    * in his parent hierarchy.
    */
   readonly attribute boolean isBelowContentBoundary;
--- a/docshell/resources/content/netError.xhtml
+++ b/docshell/resources/content/netError.xhtml
@@ -70,22 +70,18 @@
         if (desc == -1)
           return "";
 
         return decodeURIComponent(url.slice(desc + 2));
       }
 
       function retryThis(buttonEl)
       {
-        // If this is the "Offline mode" page, go online!
-        if (getErrorCode() == "netOffline") {
-          window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                .getInterface(Components.interfaces.nsIDOMWindowUtils)
-                .goOnline();
-        }
+        // Note: The application may wish to handle switching off "offline mode"
+        // before this event handler runs, but using a capturing event handler.
 
         // Session history has the URL of the page that failed
         // to load, not the one of the error page. So, just call
         // reload(), which will also repost POST data correctly.
         try {
           location.reload();
         } catch (e) {
           // We probably tried to reload a URI that caused an exception to
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -149,21 +149,19 @@ AlarmsManager.prototype = {
 
     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
 
     // Add the valid messages to be listened.
     this.initHelper(aWindow, ["AlarmsManager:Add:Return:OK", "AlarmsManager:Add:Return:KO", 
                               "AlarmsManager:GetAll:Return:OK", "AlarmsManager:GetAll:Return:KO"]);
 
     // Get the manifest URL if this is an installed app
-    this._manifestURL = null;
-    let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-    let app = utils.getApp();
-    if (app)
-      this._manifestURL = app.manifestURL;
+    let appsService = Cc["@mozilla.org/AppsService;1"]
+                        .getService(Ci.nsIAppsService);
+    this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
   },
 
   // Called from DOMRequestIpcHelper.
   uninit: function uninit() {
     debug("uninit()");
   },
 }
 
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -49,16 +49,18 @@
 #include "nsIDOMBluetoothManager.h"
 #include "BluetoothManager.h"
 #endif
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraManager.h"
 
 #include "nsIDOMGlobalPropertyInitializer.h"
 
+using namespace mozilla::dom::power;
+
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
 
 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 
@@ -1024,21 +1026,21 @@ Navigator::GetBattery(nsIDOMBatteryManag
 }
 
 NS_IMETHODIMP
 Navigator::GetMozPower(nsIDOMMozPowerManager** aPower)
 {
   *aPower = nullptr;
 
   if (!mPowerManager) {
-    nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-    NS_ENSURE_TRUE(win, NS_OK);
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window, NS_OK);
 
-    mPowerManager = new power::PowerManager();
-    mPowerManager->Init(win);
+    mPowerManager = PowerManager::CheckPermissionAndCreateInstance(window);
+    NS_ENSURE_TRUE(mPowerManager, NS_OK);
   }
 
   nsCOMPtr<nsIDOMMozPowerManager> power(mPowerManager);
   power.forget(aPower);
 
   return NS_OK;
 }
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -535,16 +535,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "nsIOpenWindowEventDetail.h"
 #include "nsIDOMGlobalObjectConstructor.h"
 
 #include "DOMFileHandle.h"
 #include "FileRequest.h"
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
 #include "mozilla/Likely.h"
+#include "nsDebug.h"
 
 #undef None // something included above defines this preprocessor symbol, maybe Xlib headers
 #include "WebGLContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -1575,16 +1576,19 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, WebGLExtensionSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(WebGLExtensionCompressedTextureS3TC, WebGLExtensionSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
+  NS_DEFINE_CLASSINFO_DATA(WebGLExtensionDepthTexture, WebGLExtensionSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS |
+                           nsIXPCScriptable::WANT_ADDPROPERTY)
 
   NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PaintRequestList, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -2068,18 +2072,20 @@ static inline nsresult
 SetParentToWindow(nsGlobalWindow *win, JSObject **parent)
 {
   MOZ_ASSERT(win);
   MOZ_ASSERT(win->IsInnerWindow());
   *parent = win->FastGetGlobalJSObject();
 
   if (MOZ_UNLIKELY(!*parent)) {
     // The only known case where this can happen is when the inner window has
-    // been torn down. See bug 691178 comment 11.
-    MOZ_ASSERT(win->IsClosedOrClosing());
+    // been torn down. See bug 691178 comment 11. Should be a fatal MOZ_ASSERT,
+    // but we've found a way to hit it too often in mochitests. See bugs 777875
+    // 778424, 781078.
+    NS_ASSERTION(win->IsClosedOrClosing(), "win should be closed or closing");
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 // static
 
 nsISupports *
@@ -4271,16 +4277,20 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionLoseContext, nsIWebGLExtensionLoseContext)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionLoseContext)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionCompressedTextureS3TC, nsIWebGLExtensionCompressedTextureS3TC)
     DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionCompressedTextureS3TC)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionDepthTexture, nsIWebGLExtensionDepthTexture)
+    DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionDepthTexture)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(PaintRequest, nsIDOMPaintRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest)
    DOM_CLASSINFO_MAP_END
  
   DOM_CLASSINFO_MAP_BEGIN(PaintRequestList, nsIDOMPaintRequestList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequestList)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -458,16 +458,17 @@ DOMCI_CLASS(WebGLRenderbuffer)
 DOMCI_CLASS(WebGLUniformLocation)
 DOMCI_CLASS(WebGLShaderPrecisionFormat)
 DOMCI_CLASS(WebGLActiveInfo)
 DOMCI_CLASS(WebGLExtension)
 DOMCI_CLASS(WebGLExtensionStandardDerivatives)
 DOMCI_CLASS(WebGLExtensionTextureFilterAnisotropic)
 DOMCI_CLASS(WebGLExtensionLoseContext)
 DOMCI_CLASS(WebGLExtensionCompressedTextureS3TC)
+DOMCI_CLASS(WebGLExtensionDepthTexture)
 
 DOMCI_CLASS(PaintRequest)
 DOMCI_CLASS(PaintRequestList)
 
 DOMCI_CLASS(ScrollAreaEvent)
 
 DOMCI_CLASS(EventListenerInfo)
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -59,17 +59,16 @@
 #include "nsIIOService.h"
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "sampler.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsIDOMFileHandle.h"
-#include "nsIDOMApplicationRegistry.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 
 static bool IsUniversalXPConnectCapable()
 {
@@ -2283,16 +2282,32 @@ nsDOMWindowUtils::CheckAndClearPaintedSt
     *aResult = false;
     return NS_OK;
   }
 
   *aResult = frame->CheckAndClearPaintedState();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDOMWindowUtils::PreventFurtherDialogs()
+{
+  // Permanently disable further dialogs for this window.
+
+  if (!IsUniversalXPConnectCapable()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+
+  static_cast<nsGlobalWindow*>(window.get())->PreventFurtherDialogs(true);
+  return NS_OK;
+}
+
 static nsresult
 GetFileOrBlob(const nsAString& aName, const jsval& aBlobParts,
               const jsval& aParameters, JSContext* aCx,
               PRUint8 aOptionalArgCount, nsISupports** aResult)
 {
   if (!IsUniversalXPConnectCapable()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
@@ -2557,57 +2572,16 @@ nsDOMWindowUtils::SetScrollPositionClamp
 
   presShell->SetScrollPositionClampingScrollPortSize(
     nsPresContext::CSSPixelsToAppUnits(aWidth),
     nsPresContext::CSSPixelsToAppUnits(aHeight));
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMWindowUtils::SetIsApp(bool aValue)
-{
-  if (!IsUniversalXPConnectCapable()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  static_cast<nsGlobalWindow*>(window.get())->SetIsApp(aValue);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMWindowUtils::SetApp(const nsAString& aManifestURL)
-{
-  if (!IsUniversalXPConnectCapable()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  return static_cast<nsGlobalWindow*>(window.get())->SetApp(aManifestURL);
-}
-
-NS_IMETHODIMP
-nsDOMWindowUtils::GetApp(mozIDOMApplication** aApplication)
-{
-  if (!IsUniversalXPConnectCapable()) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  return static_cast<nsGlobalWindow*>(window.get())->GetApp(aApplication);
-}
-
 nsresult
 nsDOMWindowUtils::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement,
                                             const nsAString& aNewOrigin)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
 
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -666,31 +666,31 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mShowFocusRings(false),
 #else
     mShowAccelerators(true),
     mShowFocusRings(true),
 #endif
     mShowFocusRingForContent(false),
     mFocusByKeyOccurred(false),
     mNotifiedIDDestroyed(false),
-    mIsApp(TriState_Unknown),
     mTimeoutInsertionPoint(nullptr),
     mTimeoutPublicIdCounter(1),
     mTimeoutFiringDepth(0),
     mJSObject(nullptr),
     mTimeoutsSuspendDepth(0),
     mFocusMethod(0),
     mSerial(0),
 #ifdef DEBUG
     mSetOpenerWindowCalled(false),
 #endif
     mCleanedUp(false),
     mCallCleanUpAfterModalDialogCloses(false),
     mDialogAbuseCount(0),
-    mDialogDisabled(false)
+    mStopAbuseDialogs(false),
+    mDialogsPermanentlyDisabled(false)
 {
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
   // Initialize timeout storage
   PR_INIT_CLIST(&mTimeouts);
@@ -2547,114 +2547,129 @@ nsGlobalWindow::PreHandleEvent(nsEventCh
        NS_IS_DRAG_EVENT(aVisitor.mEvent))) {
     mAddActiveEventFuzzTime = false;
   }
 
   return NS_OK;
 }
 
 bool
-nsGlobalWindow::DialogOpenAttempted()
-{
+nsGlobalWindow::DialogsAreBlocked(bool *aBeingAbused)
+{
+  *aBeingAbused = false;
+
   nsGlobalWindow *topWindow = GetScriptableTop();
   if (!topWindow) {
-    NS_ERROR("DialogOpenAttempted() called without a top window?");
-
-    return false;
+    NS_ERROR("DialogsAreBlocked() called without a top window?");
+    return true;
   }
 
   topWindow = topWindow->GetCurrentInnerWindowInternal();
-  if (!topWindow ||
-      topWindow->mLastDialogQuitTime.IsNull() ||
+  if (!topWindow) {
+    return true;
+  }
+
+  if (topWindow->mDialogsPermanentlyDisabled) {
+    return true;
+  }
+
+  // Dialogs are blocked if the content viewer is hidden
+  if (mDocShell) {
+    nsCOMPtr<nsIContentViewer> cv;
+    mDocShell->GetContentViewer(getter_AddRefs(cv));
+
+    bool isHidden;
+    cv->GetIsHidden(&isHidden);
+    if (isHidden) {
+      return true;
+    }
+  }
+
+  *aBeingAbused = topWindow->DialogsAreBeingAbused();
+
+  return topWindow->mStopAbuseDialogs && *aBeingAbused;
+}
+
+bool
+nsGlobalWindow::DialogsAreBeingAbused()
+{
+  NS_ASSERTION(GetScriptableTop() &&
+               GetScriptableTop()->GetCurrentInnerWindowInternal() == this,
+               "DialogsAreBeingAbused called with invalid window");
+            
+  if (mLastDialogQuitTime.IsNull() ||
       nsContentUtils::CallerHasUniversalXPConnect()) {
     return false;
   }
-
-  TimeDuration dialogDuration(TimeStamp::Now() -
-                              topWindow->mLastDialogQuitTime);
-
-  if (dialogDuration.ToSeconds() <
-        Preferences::GetInt("dom.successive_dialog_time_limit",
-                            SUCCESSIVE_DIALOG_TIME_LIMIT)) {
-    topWindow->mDialogAbuseCount++;
-
-    return (topWindow->GetPopupControlState() > openAllowed ||
-            topWindow->mDialogAbuseCount > MAX_DIALOG_COUNT);
-  }
-
-  topWindow->mDialogAbuseCount = 0;
+ 
+  TimeDuration dialogInterval(TimeStamp::Now() - mLastDialogQuitTime);
+  if (dialogInterval.ToSeconds() <
+      Preferences::GetInt("dom.successive_dialog_time_limit",
+                          DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)) {
+    mDialogAbuseCount++;
+
+    return GetPopupControlState() > openAllowed ||
+           mDialogAbuseCount > MAX_SUCCESSIVE_DIALOG_COUNT;
+  }
+
+  // Reset the abuse counter
+  mDialogAbuseCount = 0;
 
   return false;
 }
 
 bool
-nsGlobalWindow::AreDialogsBlocked()
-{
-  nsGlobalWindow *topWindow = GetScriptableTop();
-  if (!topWindow) {
-    NS_ASSERTION(!mDocShell, "AreDialogsBlocked() called without a top window?");
-
-    return true;
-  }
-
-  topWindow = topWindow->GetCurrentInnerWindowInternal();
-
-  return !topWindow ||
-         (topWindow->mDialogDisabled &&
-          (topWindow->GetPopupControlState() > openAllowed ||
-           topWindow->mDialogAbuseCount >= MAX_DIALOG_COUNT));
-}
-
-bool
-nsGlobalWindow::ConfirmDialogAllowed()
-{
-  FORWARD_TO_OUTER(ConfirmDialogAllowed, (), false);
+nsGlobalWindow::ConfirmDialogIfNeeded()
+{
+  FORWARD_TO_OUTER(ConfirmDialogIfNeeded, (), false);
 
   NS_ENSURE_TRUE(mDocShell, false);
   nsCOMPtr<nsIPromptService> promptSvc =
     do_GetService("@mozilla.org/embedcomp/prompt-service;1");
 
-  if (!DialogOpenAttempted() || !promptSvc) {
+  if (!promptSvc) {
     return true;
   }
 
   // Reset popup state while opening a modal dialog, and firing events
   // about the dialog, to prevent the current state from being active
   // the whole time a modal dialog is open.
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
   bool disableDialog = false;
   nsXPIDLString label, title;
   nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                      "ScriptDialogLabel", label);
   nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                      "ScriptDialogPreventTitle", title);
   promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
   if (disableDialog) {
-    PreventFurtherDialogs();
+    PreventFurtherDialogs(false);
     return false;
   }
 
   return true;
 }
 
 void
-nsGlobalWindow::PreventFurtherDialogs()
+nsGlobalWindow::PreventFurtherDialogs(bool aPermanent)
 {
   nsGlobalWindow *topWindow = GetScriptableTop();
   if (!topWindow) {
     NS_ERROR("PreventFurtherDialogs() called without a top window?");
-
     return;
   }
 
   topWindow = topWindow->GetCurrentInnerWindowInternal();
-
-  if (topWindow)
-    topWindow->mDialogDisabled = true;
+  if (topWindow) {
+    topWindow->mStopAbuseDialogs = true;
+    if (aPermanent) {
+      topWindow->mDialogsPermanentlyDisabled = true;
+    }
+  }
 }
 
 nsresult
 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
 
   // Return early if there is nothing to do.
@@ -4317,21 +4332,23 @@ nsGlobalWindow::GetScrollXY(PRInt32* aSc
   nsPoint scrollPos = sf->GetScrollPosition();
   if (scrollPos != nsPoint(0,0) && !aDoFlush) {
     // Oh, well.  This is the expensive case -- the window is scrolled and we
     // didn't actually flush yet.  Repeat, but with a flush, since the content
     // may get shorter and hence our scroll position may decrease.
     return GetScrollXY(aScrollX, aScrollY, true);
   }
 
-  if (aScrollX)
-    *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
-  if (aScrollY)
-    *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
-
+  nsIntPoint scrollPosCSSPixels = sf->GetScrollPositionCSSPixels();
+  if (aScrollX) {
+    *aScrollX = scrollPosCSSPixels.x;
+  }
+  if (aScrollY) {
+    *aScrollY = scrollPosCSSPixels.y;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
 {
   NS_ENSURE_ARG_POINTER(aScrollX);
   *aScrollX = 0;
@@ -4786,22 +4803,20 @@ nsGlobalWindow::CanMoveResizeWindows()
   return true;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Alert(const nsAString& aString)
 {
   FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
 
-  if (AreDialogsBlocked())
+  bool needToPromptForAbuse;
+  if (DialogsAreBlocked(&needToPromptForAbuse)) {
     return NS_ERROR_NOT_AVAILABLE;
-
-  // We have to capture this now so as not to get confused with the
-  // popup state we push next
-  bool shouldEnableDisableDialog = DialogOpenAttempted();
+  }
 
   // Reset popup state while opening a modal dialog, and firing events
   // about the dialog, to prevent the current state from being active
   // the whole time a modal dialog is open.
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
   // Special handling for alert(null) in JS for backwards
   // compatibility.
@@ -4838,44 +4853,42 @@ nsGlobalWindow::Alert(const nsAString& a
 
   nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
   if (promptBag)
     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
 
   nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                              GetCurrentInnerWindowInternal()->mDoc :
                              nullptr);
-  if (shouldEnableDisableDialog) {
+  if (needToPromptForAbuse) {
     bool disallowDialog = false;
     nsXPIDLString label;
     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                        "ScriptDialogLabel", label);
 
     rv = prompt->AlertCheck(title.get(), final.get(), label.get(),
                             &disallowDialog);
     if (disallowDialog)
-      PreventFurtherDialogs();
+      PreventFurtherDialogs(false);
   } else {
     rv = prompt->Alert(title.get(), final.get());
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Confirm(const nsAString& aString, bool* aReturn)
 {
   FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
 
-  if (AreDialogsBlocked())
+  bool needToPromptForAbuse;
+  if (DialogsAreBlocked(&needToPromptForAbuse)) {
     return NS_ERROR_NOT_AVAILABLE;
-
-  // We have to capture this now so as not to get confused with the popup state
-  // we push next
-  bool shouldEnableDisableDialog = DialogOpenAttempted();
+  }
 
   // Reset popup state while opening a modal dialog, and firing events
   // about the dialog, to prevent the current state from being active
   // the whole time a modal dialog is open.
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
   *aReturn = false;
 
@@ -4907,48 +4920,46 @@ nsGlobalWindow::Confirm(const nsAString&
 
   nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
   if (promptBag)
     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
 
   nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                              GetCurrentInnerWindowInternal()->mDoc :
                              nullptr);
-  if (shouldEnableDisableDialog) {
+  if (needToPromptForAbuse) {
     bool disallowDialog = false;
     nsXPIDLString label;
     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                        "ScriptDialogLabel", label);
 
     rv = prompt->ConfirmCheck(title.get(), final.get(), label.get(),
                               &disallowDialog, aReturn);
     if (disallowDialog)
-      PreventFurtherDialogs();
+      PreventFurtherDialogs(false);
   } else {
     rv = prompt->Confirm(title.get(), final.get(), aReturn);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
                        nsAString& aReturn)
 {
   FORWARD_TO_OUTER(Prompt, (aMessage, aInitial, aReturn),
                    NS_ERROR_NOT_INITIALIZED);
 
   SetDOMStringToNull(aReturn);
 
-  if (AreDialogsBlocked())
+  bool needToPromptForAbuse;
+  if (DialogsAreBlocked(&needToPromptForAbuse)) {
     return NS_ERROR_NOT_AVAILABLE;
-
-  // We have to capture this now so as not to get confused with the popup state
-  // we push next
-  bool shouldEnableDisableDialog = DialogOpenAttempted();
+  }
 
   // Reset popup state while opening a modal dialog, and firing events
   // about the dialog, to prevent the current state from being active
   // the whole time a modal dialog is open.
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
   // Before bringing up the window, unsuppress painting and flush
   // pending reflows.
@@ -4981,30 +4992,30 @@ nsGlobalWindow::Prompt(const nsAString& 
   if (promptBag)
     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
 
   // Pass in the default value, if any.
   PRUnichar *inoutValue = ToNewUnicode(fixedInitial);
   bool disallowDialog = false;
 
   nsXPIDLString label;
-  if (shouldEnableDisableDialog) {
+  if (needToPromptForAbuse) {
     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                        "ScriptDialogLabel", label);
   }
 
   nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                              GetCurrentInnerWindowInternal()->mDoc :
                              nullptr);
   bool ok;
   rv = prompt->Prompt(title.get(), fixedMessage.get(),
                       &inoutValue, label.get(), &disallowDialog, &ok);
 
   if (disallowDialog) {
-    PreventFurtherDialogs();
+    PreventFurtherDialogs(false);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAdoptingString outValue(inoutValue);
 
   if (ok && outValue) {
     aReturn.Assign(outValue);
@@ -5252,18 +5263,24 @@ NS_IMETHODIMP
 nsGlobalWindow::Print()
 {
 #ifdef NS_PRINTING
   FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
 
   if (Preferences::GetBool("dom.disable_window_print", false))
     return NS_ERROR_NOT_AVAILABLE;
 
-  if (AreDialogsBlocked() || !ConfirmDialogAllowed())
+  bool needToPromptForAbuse;
+  if (DialogsAreBlocked(&needToPromptForAbuse)) {
     return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (needToPromptForAbuse && !ConfirmDialogIfNeeded()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
   if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
                                 getter_AddRefs(webBrowserPrint)))) {
     nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                                GetCurrentInnerWindowInternal()->mDoc :
                                nullptr);
 
@@ -7184,18 +7201,24 @@ nsGlobalWindow::ShowModalDialog(const ns
 
   if (Preferences::GetBool("dom.disable_window_showModalDialog", false))
     return NS_ERROR_NOT_AVAILABLE;
 
   // Before bringing up the window/dialog, unsuppress painting and flush
   // pending reflows.
   EnsureReflowFlushAndPaint();
 
-  if (AreDialogsBlocked() || !ConfirmDialogAllowed())
+  bool needToPromptForAbuse;
+  if (DialogsAreBlocked(&needToPromptForAbuse)) {
     return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (needToPromptForAbuse && !ConfirmDialogIfNeeded()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
   nsCOMPtr<nsIDOMWindow> dlgWin;
   nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
 
   ConvertDialogOptions(aOptions, options);
 
   options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
 
@@ -9031,17 +9054,17 @@ nsGlobalWindow::CloneStorageEvent(const 
   domEvent->GetCancelable(&cancelable);
 
   aEvent->GetKey(key);
   aEvent->GetOldValue(oldValue);
   aEvent->GetNewValue(newValue);
   aEvent->GetUrl(url);
   aEvent->GetStorageArea(getter_AddRefs(storageArea));
 
-  NS_NewDOMStorageEvent(getter_AddRefs(domEvent), nsnull, nsnull);
+  NS_NewDOMStorageEvent(getter_AddRefs(domEvent), nullptr, nullptr);
   aEvent = do_QueryInterface(domEvent);
   return aEvent->InitStorageEvent(aType, canBubble, cancelable,
                                   key, oldValue, newValue,
                                   url, storageArea);
 }
 
 nsresult
 nsGlobalWindow::FireDelayedDOMEvents()
@@ -9158,18 +9181,25 @@ nsGlobalWindow::OpenInternal(const nsASt
   if (!chrome) {
     // No chrome means we don't want to go through with this open call
     // -- see nsIWindowWatcher.idl
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ASSERTION(mDocShell, "Must have docshell here");
 
+  // Popups from apps are never blocked.
+  bool isApp = false;
+  if (mDoc) {
+    isApp = mDoc->NodePrincipal()->GetAppStatus() >=
+              nsIPrincipal::APP_STATUS_INSTALLED;
+  }
+
   const bool checkForPopup = !nsContentUtils::IsCallerChrome() &&
-    !IsPartOfApp() && !aDialog && !WindowExists(aName, !aCalledNoScript);
+    !isApp && !aDialog && !WindowExists(aName, !aCalledNoScript);
 
   // Note: it's very important that this be an nsXPIDLCString, since we want
   // .get() on it to return nullptr until we write stuff to it.  The window
   // watcher expects a null URL string if there is no URL to load.
   nsXPIDLCString url;
   nsresult rv = NS_OK;
 
   // It's important to do this security check before determining whether this
@@ -10666,122 +10696,16 @@ nsGlobalWindow::SizeOfIncludingThis(nsWi
     }
   }
 
   aWindowSizes->mDOMOther +=
     mNavigator ?
       mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf) : 0;
 }
 
-void
-nsGlobalWindow::SetIsApp(bool aValue)
-{
-  FORWARD_TO_OUTER_VOID(SetIsApp, (aValue));
-
-  // You shouldn't call SetIsApp() more than once.
-  MOZ_ASSERT(mIsApp == TriState_Unknown);
-
-  mIsApp = aValue ? TriState_True : TriState_False;
-}
-
-bool
-nsGlobalWindow::IsInAppOrigin()
-{
-  FORWARD_TO_OUTER(IsInAppOrigin, (), false);
-
-  nsIPrincipal* principal = GetPrincipal();
-  NS_ENSURE_TRUE(principal != nullptr, false);
-
-  // We go trough all window parents until we find one with |mIsApp| set to
-  // something. If none is found, we are not part of an application.
-  for (nsGlobalWindow* w = static_cast<nsGlobalWindow*>(this); w;
-      w = static_cast<nsGlobalWindow*>(w->GetParentInternal())) {
-    if (w->mIsApp == TriState_True) {
-      // The window should be part of an application.
-      MOZ_ASSERT(w->mApp);
-      bool sameOrigin = false;
-      return w->mAppPrincipal &&
-             principal &&
-             NS_SUCCEEDED(principal->Equals(w->mAppPrincipal, &sameOrigin)) &&
-             sameOrigin;
-    } else if (w->mIsApp == TriState_False) {
-      return false;
-    }
-  }
-
-  return false;
-}
-
-bool
-nsGlobalWindow::IsPartOfApp()
-{
-  nsCOMPtr<mozIDOMApplication> app;
-
-  return NS_SUCCEEDED(GetApp(getter_AddRefs(app))) ? app != nullptr : false;
-}
-
-nsresult
-nsGlobalWindow::SetApp(const nsAString& aManifestURL)
-{
-  // SetIsApp(true) should be called before calling SetApp().
-  if (mIsApp != TriState_True) {
-    MOZ_ASSERT(false);
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
-  if (!appsService) {
-    NS_ERROR("Apps Service is not available!");
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<mozIDOMApplication> app;
-  appsService->GetAppByManifestURL(aManifestURL, getter_AddRefs(app));
-  if (!app) {
-    NS_WARNING("No application found with the specified manifest URL");
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIURI> uri;
-  nsresult res = NS_NewURI(getter_AddRefs(uri), aManifestURL);
-  NS_ENSURE_SUCCESS(res, res);
-
-  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
-  res = ssm->GetSimpleCodebasePrincipal(uri, getter_AddRefs(mAppPrincipal));
-  NS_ENSURE_SUCCESS(res, res);
-
-  mApp = app.forget();
-
-  return NS_OK;
-}
-
-nsresult
-nsGlobalWindow::GetApp(mozIDOMApplication** aApplication)
-{
-  *aApplication = nullptr;
-
-  FORWARD_TO_OUTER(GetApp, (aApplication), NS_OK);
-
-  // We go trough all window parents until we find one with |mIsApp| set to
-  // something. If none is found, we are not part of an application.
-  for (nsGlobalWindow* w = this; w;
-       w = static_cast<nsGlobalWindow*>(w->GetParentInternal())) {
-    if (w->mIsApp == TriState_True) {
-      // The window should be part of an application.
-      MOZ_ASSERT(w->mApp);
-      NS_IF_ADDREF(*aApplication = w->mApp);
-      return NS_OK;
-    } else if (w->mIsApp == TriState_False) {
-      return NS_OK;
-    }
-  }
-
-  return NS_OK;
-}
-
 // nsGlobalChromeWindow implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
                                                   nsGlobalWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -69,21 +69,21 @@
 // JS includes
 #include "jsapi.h"
 
 #define DEFAULT_HOME_PAGE "www.mozilla.org"
 #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
 
 // Amount of time allowed between alert/prompt/confirm before enabling
 // the stop dialog checkbox.
-#define SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec
+#define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec
 
-// During click or mousedown events (and others, see nsDOMEvent) we allow modal
-// dialogs up to this limit, even if they were disabled.
-#define MAX_DIALOG_COUNT 10
+// Maximum number of successive dialogs before we prompt users to disable
+// dialogs for this window.
+#define MAX_SUCCESSIVE_DIALOG_COUNT 5
 
 // Idle fuzz time upper limit
 #define MAX_IDLE_FUZZ_TIME_MS 90000
 
 // Min idle notification time in seconds.
 #define MIN_IDLE_NOTIFICATION_TIME_S 1
 
 class nsIDOMBarProp;
@@ -379,18 +379,16 @@ public:
   virtual NS_HIDDEN_(bool) CanClose();
   virtual NS_HIDDEN_(nsresult) ForceClose();
 
   virtual NS_HIDDEN_(void) MaybeUpdateTouchState();
   virtual NS_HIDDEN_(void) UpdateTouchState();
   virtual NS_HIDDEN_(bool) DispatchCustomEvent(const char *aEventName);
   virtual NS_HIDDEN_(void) RefreshCompartmentPrincipal();
   virtual NS_HIDDEN_(nsresult) SetFullScreenInternal(bool aIsFullScreen, bool aRequireTrust);
-  virtual NS_HIDDEN_(bool) IsPartOfApp();
-  virtual NS_HIDDEN_(bool) IsInAppOrigin();
 
   // nsIDOMStorageIndexedDB
   NS_DECL_NSIDOMSTORAGEINDEXEDDB
 
   // nsIInterfaceRequestor
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // Object Management
@@ -435,32 +433,32 @@ public:
     nsCOMPtr<nsIDOMWindow> top;
     GetScriptableTop(getter_AddRefs(top));
     if (top) {
       return static_cast<nsGlobalWindow *>(top.get());
     }
     return nullptr;
   }
 
-  // Call this when a modal dialog is about to be opened.  Returns
-  // true if we've reached the state in this top level window where we
-  // ask the user if further dialogs should be blocked.
-  bool DialogOpenAttempted();
+  // Returns true if dialogs need to be prevented from appearings for this
+  // window. beingAbused returns whether dialogs are being abused.
+  bool DialogsAreBlocked(bool *aBeingAbused);
 
-  // Returns true if dialogs have already been blocked for this
-  // window.
-  bool AreDialogsBlocked();
+  // Returns true if we've reached the state in this top level window where we
+  // ask the user if further dialogs should be blocked. This method must only
+  // be called on the scriptable top inner window.
+  bool DialogsAreBeingAbused();
 
-  // Ask the user if further dialogs should be blocked. This is used
-  // in the cases where we have no modifiable UI to show, in that case
-  // we show a separate dialog when asking this question.
-  bool ConfirmDialogAllowed();
+  // Ask the user if further dialogs should be blocked, if dialogs are currently
+  // being abused. This is used in the cases where we have no modifiable UI to
+  // show, in that case we show a separate dialog to ask this question.
+  bool ConfirmDialogIfNeeded();
 
   // Prevent further dialogs in this (top level) window
-  void PreventFurtherDialogs();
+  void PreventFurtherDialogs(bool aPermanent);
 
   virtual void SetHasAudioAvailableEventListeners();
 
   nsIScriptContext *GetContextInternal()
   {
     if (mOuterWindow) {
       return GetOuterWindowInternal()->mContext;
     }
@@ -621,22 +619,16 @@ protected:
 
   nsCOMPtr <nsIIdleService> mIdleService;
 
   static bool sIdleObserversAPIFuzzTimeDisabled;
 
   friend class HashchangeCallback;
   friend class nsBarProp;
 
-  enum TriState {
-    TriState_Unknown = -1,
-    TriState_False,
-    TriState_True
-  };
-
   // Object Management
   virtual ~nsGlobalWindow();
   void CleanUp(bool aIgnoreModalDialog);
   void ClearControllers();
   nsresult FinalClose();
 
   inline void MaybeClearInnerWindow(nsGlobalWindow* aExpectedInner)
   {
@@ -893,20 +885,16 @@ protected:
 
   inline PRInt32 DOMMinTimeoutValue() const;
 
   nsresult CreateOuterObject(nsGlobalWindow* aNewInner);
   nsresult SetOuterObject(JSContext* aCx, JSObject* aOuterObject);
   nsresult CloneStorageEvent(const nsAString& aType,
                              nsCOMPtr<nsIDOMStorageEvent>& aEvent);
 
-  void SetIsApp(bool aValue);
-  nsresult SetApp(const nsAString& aManifestURL);
-  nsresult GetApp(mozIDOMApplication** aApplication);
-
   // Implements Get{Real,Scriptable}Top.
   nsresult GetTopImpl(nsIDOMWindow **aWindow, bool aScriptable);
 
   // Helper for creating performance objects.
   void CreatePerformanceObjectIfNeeded();
 
   // When adding new member variables, be careful not to create cycles
   // through JavaScript.  If there is any chance that a member variable
@@ -972,24 +960,16 @@ protected:
 
   // true if tab navigation has occurred for this window. Focus rings
   // should be displayed.
   bool                   mFocusByKeyOccurred : 1;
 
   // whether we've sent the destroy notification for our window id
   bool                   mNotifiedIDDestroyed : 1;
 
-  // Whether the window is the window of an application frame.
-  // This is TriState_Unknown if the object is the content window of an
-  // iframe which is neither mozBrowser nor mozApp.
-  TriState               mIsApp : 2;
-
-  // Principal of the web app running in this window, if any.
-  nsCOMPtr<nsIPrincipal>        mAppPrincipal;
-
   nsCOMPtr<nsIScriptContext>    mContext;
   nsWeakPtr                     mOpener;
   nsCOMPtr<nsIControllers>      mControllers;
   nsCOMPtr<nsIArray>            mArguments;
   nsCOMPtr<nsIArray>            mArgumentsLast;
   nsCOMPtr<nsIPrincipal>        mArgumentsOrigin;
   nsRefPtr<Navigator>           mNavigator;
   nsRefPtr<nsScreen>            mScreen;
@@ -1057,38 +1037,44 @@ protected:
   nsCOMPtr<nsIDOMOfflineResourceList> mApplicationCache;
 
   nsDataHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*> mCachedXBLPrototypeHandlers;
 
   nsCOMPtr<nsIDocument> mSuspendedDoc;
 
   nsCOMPtr<nsIIDBFactory> mIndexedDB;
 
-  // In the case of a "trusted" dialog (@see PopupControlState), we
-  // set this counter to ensure a max of MAX_DIALOG_LIMIT
+  // This counts the number of windows that have been opened in rapid succession
+  // (i.e. within dom.successive_dialog_time_limit of each other). It is reset
+  // to 0 once a dialog is opened after dom.successive_dialog_time_limit seconds
+  // have elapsed without any other dialogs.
   PRUint32                      mDialogAbuseCount;
 
-  // This holds the time when the last modal dialog was shown, if two
-  // dialogs are shown within CONCURRENT_DIALOG_TIME_LIMIT the
-  // checkbox is shown. In the case of ShowModalDialog another Confirm
-  // dialog will be shown, the result of the checkbox/confirm dialog
-  // will be stored in mDialogDisabled variable.
+  // This holds the time when the last modal dialog was shown. If more than
+  // MAX_DIALOG_LIMIT dialogs are shown within the time span defined by
+  // dom.successive_dialog_time_limit, we show a checkbox or confirmation prompt
+  // to allow disabling of further dialogs from this window.
   TimeStamp                     mLastDialogQuitTime;
-  bool                          mDialogDisabled;
+
+  // This is set to true once the user has opted-in to preventing further
+  // dialogs for this window. Subsequent dialogs may still open if
+  // mDialogAbuseCount gets reset.
+  bool                          mStopAbuseDialogs;
+
+  // This flag gets set when dialogs should be permanently disabled for this
+  // window (e.g. when we are closing the tab and therefore are guaranteed to be
+  // destroying this window).
+  bool                          mDialogsPermanentlyDisabled;
 
   nsRefPtr<nsDOMMozURLProperty> mURLProperty;
 
   nsTHashtable<nsPtrHashKey<nsDOMEventTargetHelper> > mEventTargetObjects;
 
   nsTArray<PRUint32> mEnabledSensors;
 
-  // The application associated with this window.
-  // This should only be non-null if mIsApp's value is TriState_True.
-  nsCOMPtr<mozIDOMApplication> mApp;
-
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class PostMessageEvent;
 
   static WindowByIdTable* sWindowsById;
   static bool sWarnedAboutWindowInternal;
 };
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -43,18 +43,18 @@ class nsIDocument;
 class nsIScriptTimeoutHandler;
 struct nsTimeout;
 template <class> class nsScriptObjectHolder;
 class nsXBLPrototypeHandler;
 class nsIArray;
 class nsPIWindowRoot;
 
 #define NS_PIDOMWINDOW_IID \
-{ 0x0c4d0b84, 0xb524, 0x4572, \
-  { 0x8e, 0xd1, 0x7f, 0x78, 0x14, 0x7c, 0x4d, 0xf1 } }
+{0x05995519, 0xde6e, 0x428c, \
+  {0x9e, 0x96, 0x61, 0xd6, 0x0f, 0x34, 0x45, 0x3e}}
 
 class nsPIDOMWindow : public nsIDOMWindowInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMWINDOW_IID)
 
   virtual nsPIDOMWindow* GetPrivateRoot() = 0;
 
@@ -604,29 +604,16 @@ public:
   virtual bool DispatchCustomEvent(const char *aEventName) = 0;
 
   /**
    * Notify the active inner window that the document principal may have changed
    * and that the compartment principal needs to be updated.
    */
   virtual void RefreshCompartmentPrincipal() = 0;
 
-  /**
-   * Returns if the window is part of an application.
-   * It will check for the window app state and its parents until a window has
-   * an app state different from |TriState_Unknown|.
-   */
-  virtual bool IsPartOfApp() = 0;
-
-  /**
-   * Returns true if this window is part of a web app and has the same origin
-   * (principal) as the app.
-   */
-  virtual bool IsInAppOrigin() = 0;
-
 protected:
   // The nsPIDOMWindow constructor. The aOuterWindow argument should
   // be null if and only if the created window itself is an outer
   // window. In all other cases aOuterWindow should be the outer
   // window for the inner window that is being created.
   nsPIDOMWindow(nsPIDOMWindow *aOuterWindow);
 
   ~nsPIDOMWindow();
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -348,50 +348,71 @@ nsScreen::MozLockOrientation(const nsASt
   } else if (aOrientation.EqualsLiteral("landscape-primary")) {
     orientation = eScreenOrientation_LandscapePrimary;
   } else if (aOrientation.EqualsLiteral("landscape-secondary")) {
     orientation = eScreenOrientation_LandscapeSecondary;
   } else {
     return NS_OK;
   }
 
-  if (!GetOwner()) {
-    return NS_OK;
-  }
+  // Determine whether we can lock the screen orientation.
+  bool canLockOrientation = false;
+  do {
+    nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
+    if (!owner) {
+      break;
+    }
 
-  // Chrome code and apps can always lock the screen orientation.
-  if (!IsChromeType(GetOwner()->GetDocShell()) &&
-      !static_cast<nsGlobalWindow*>(GetOwner())->IsPartOfApp()) {
-    nsCOMPtr<nsIDOMDocument> doc;
-    GetOwner()->GetDocument(getter_AddRefs(doc));
-    if (!doc) {
-      return NS_OK;
+    // Chrome can always lock the screen orientation.
+    if (IsChromeType(owner->GetDocShell())) {
+      canLockOrientation = true;
+      break;
     }
 
-    // Non-apps content can lock orientation only if fullscreen.
-    bool fullscreen;
-    doc->GetMozFullScreen(&fullscreen);
-    if (!fullscreen) {
-      return NS_OK;
+    nsCOMPtr<nsIDOMDocument> domDoc;
+    owner->GetDocument(getter_AddRefs(domDoc));
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+    if (!doc) {
+      break;
     }
 
-    nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
+    // Apps can always lock the screen orientation.
+    if (doc->NodePrincipal()->GetAppStatus() >=
+          nsIPrincipal::APP_STATUS_INSTALLED) {
+      canLockOrientation = true;
+      break;
+    }
+
+    // Other content must be full-screen in order to lock orientation.
+    bool fullscreen;
+    domDoc->GetMozFullScreen(&fullscreen);
+    if (!fullscreen) {
+      break;
+    }
+
+    // If we're full-screen, register a listener so we learn when we leave
+    // full-screen.
+    nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(owner);
     if (!target) {
-      return NS_OK;
+      break;
     }
 
     if (!mEventListener) {
       mEventListener = new FullScreenEventListener();
     }
 
     target->AddSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"),
-                                   mEventListener, true);
+                                   mEventListener, /* useCapture = */ true);
+    canLockOrientation = true;
+  } while(0);
+
+  if (canLockOrientation) {
+    *aReturn = hal::LockScreenOrientation(orientation);
   }
 
-  *aReturn = hal::LockScreenOrientation(orientation);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreen::MozUnlockOrientation()
 {
   hal::UnlockScreenOrientation();
   return NS_OK;
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -59,16 +59,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 
 BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue)
     : BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
+    , mEnabled(false)
+    , mDiscoverable(false)
+    , mDiscovering(false)
+    , mPairable(false)
+    , mPowered(false)
     , mJsUuids(nullptr)
     , mJsDeviceAddresses(nullptr)
     , mIsRooted(false)
 {
   BindToOwner(aOwner);
   const InfallibleTArray<BluetoothNamedValue>& values =
     aValue.get_ArrayOfBluetoothNamedValue();
   for (uint32_t i = 0; i < values.Length(); ++i) {
@@ -353,42 +358,42 @@ BluetoothAdapter::GetUuids(JSContext* aC
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BluetoothAdapter::SetName(const nsAString& aName,
                           nsIDOMDOMRequest** aRequest)
 {
   if (mName.Equals(aName)) {
-    return NS_OK;
+    return FirePropertyAlreadySet(GetOwner(), aRequest);
   }
   nsString name(aName);
   BluetoothValue value(name);
   BluetoothNamedValue property(NS_LITERAL_STRING("Name"), value);
   return SetProperty(GetOwner(), property, aRequest);
 }
  
 NS_IMETHODIMP
 BluetoothAdapter::SetDiscoverable(const bool aDiscoverable,
                                   nsIDOMDOMRequest** aRequest)
 {
   if (aDiscoverable == mDiscoverable) {
-    return NS_OK;
+    return FirePropertyAlreadySet(GetOwner(), aRequest);
   }
   BluetoothValue value(aDiscoverable);
   BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"), value);
   return SetProperty(GetOwner(), property, aRequest);
 }
  
 NS_IMETHODIMP
 BluetoothAdapter::SetDiscoverableTimeout(const PRUint32 aDiscoverableTimeout,
                                          nsIDOMDOMRequest** aRequest)
 {
   if (aDiscoverableTimeout == mDiscoverableTimeout) {
-    return NS_OK;
+    return FirePropertyAlreadySet(GetOwner(), aRequest);
   }
   BluetoothValue value(aDiscoverableTimeout);
   BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value);
   return SetProperty(GetOwner(), property, aRequest);
 }
 
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, propertychanged)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicefound)
--- a/dom/bluetooth/BluetoothPropertyContainer.cpp
+++ b/dom/bluetooth/BluetoothPropertyContainer.cpp
@@ -8,25 +8,36 @@
 #include "BluetoothPropertyContainer.h"
 #include "BluetoothService.h"
 #include "BluetoothTypes.h"
 #include "nsIDOMDOMRequest.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 nsresult
-BluetoothPropertyContainer::GetProperties()
+BluetoothPropertyContainer::FirePropertyAlreadySet(nsIDOMWindow* aOwner,
+                                                   nsIDOMDOMRequest** aRequest)
 {
-  BluetoothService* bs = BluetoothService::Get();
-  if (!bs) {
-    NS_WARNING("Bluetooth service not available!");
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+    
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
-  nsRefPtr<BluetoothReplyRunnable> task = new GetPropertiesTask(this, NULL);
-  return bs->GetProperties(mObjectType, mPath, task);
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOMRequest!");
+    return NS_ERROR_FAILURE;
+  }
+  rs->FireSuccess(req, JSVAL_VOID);
+  req.forget(aRequest);
+
+  return NS_OK;
 }
 
 nsresult
 BluetoothPropertyContainer::SetProperty(nsIDOMWindow* aOwner,
                                         const BluetoothNamedValue& aProperty,
                                         nsIDOMDOMRequest** aRequest)
 {
   BluetoothService* bs = BluetoothService::Get();
@@ -51,26 +62,8 @@ BluetoothPropertyContainer::SetProperty(
   nsRefPtr<BluetoothReplyRunnable> task = new BluetoothVoidReplyRunnable(req);
   
   rv = bs->SetProperty(mObjectType, mPath, aProperty, task);
   NS_ENSURE_SUCCESS(rv, rv);
   
   req.forget(aRequest);
   return NS_OK;
 }
-
-
-bool
-BluetoothPropertyContainer::GetPropertiesTask::ParseSuccessfulReply(jsval* aValue)
-{
-  *aValue = JSVAL_VOID;
-  BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
-  if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
-    NS_WARNING("Not a BluetoothNamedValue array!");
-    return false;
-  }
-  const InfallibleTArray<BluetoothNamedValue>& values =
-    mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
-  for (uint32_t i = 0; i < values.Length(); ++i) {
-    mPropObjPtr->SetPropertyByValue(values[i]);
-  }
-  return true;
-}
--- a/dom/bluetooth/BluetoothPropertyContainer.h
+++ b/dom/bluetooth/BluetoothPropertyContainer.h
@@ -15,17 +15,18 @@ class nsIDOMWindow;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothNamedValue;
 
 class BluetoothPropertyContainer
 {
 public:
-  nsresult GetProperties();
+  nsresult FirePropertyAlreadySet(nsIDOMWindow* aOwner,
+                                  nsIDOMDOMRequest** aRequest);
   nsresult SetProperty(nsIDOMWindow* aOwner,
                        const BluetoothNamedValue& aProperty,
                        nsIDOMDOMRequest** aRequest);
   virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) = 0;
   nsString GetPath()
   {
     return mPath;
   }
@@ -37,39 +38,16 @@ public:
 
 protected:
   BluetoothPropertyContainer(BluetoothObjectType aType) :
     mObjectType(aType)
   {}
 
   ~BluetoothPropertyContainer()
   {}
-  
-  class GetPropertiesTask : public BluetoothReplyRunnable
-  {
-  public:
-    GetPropertiesTask(BluetoothPropertyContainer* aPropObj, nsIDOMDOMRequest* aReq) :
-      BluetoothReplyRunnable(aReq),
-      mPropObjPtr(aPropObj)
-    {
-      MOZ_ASSERT(aReq && aPropObj);
-    }
-
-    virtual bool ParseSuccessfulReply(jsval* aValue);
-    
-    void
-    ReleaseMembers()
-    {
-      BluetoothReplyRunnable::ReleaseMembers();
-      mPropObjPtr = nullptr;
-    }
-    
-  private:
-    BluetoothPropertyContainer* mPropObjPtr;    
-  };
 
   nsString mPath;
   BluetoothObjectType mObjectType;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -238,17 +238,17 @@ RunDBusCallback(DBusMessage* aMsg, void*
   MOZ_ASSERT(!NS_IsMainThread());
   nsRefPtr<BluetoothReplyRunnable> replyRunnable =
     dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
 
   NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
 
   nsString replyError;
   BluetoothValue v;
-  aFunc(aMsg, nsnull, v, replyError);
+  aFunc(aMsg, nullptr, v, replyError);
   DispatchBluetoothReply(replyRunnable, v, replyError);  
 }
 
 void
 GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackObjectPathMessage);
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -65,16 +65,20 @@ BrowserElementChild.prototype = {
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   _init: function() {
     debug("Starting up.");
     sendAsyncMsg("hello");
 
+    // Set the docshell's name according to our <iframe>'s name attribute.
+    docShell.QueryInterface(Ci.nsIDocShellTreeItem).name =
+      sendSyncMsg('get-name')[0];
+
     BrowserElementPromptService.mapWindowToBrowserElementChild(content, this);
 
     docShell.QueryInterface(Ci.nsIWebProgress)
             .addProgressListener(this._progressListener,
                                  Ci.nsIWebProgress.NOTIFY_LOCATION |
                                  Ci.nsIWebProgress.NOTIFY_SECURITY |
                                  Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
 
@@ -82,36 +86,16 @@ BrowserElementChild.prototype = {
             .sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
                                 .createInstance(Ci.nsISHistory);
 
     // This is necessary to get security web progress notifications.
     var securityUI = Cc['@mozilla.org/secure_browser_ui;1']
                        .createInstance(Ci.nsISecureBrowserUI);
     securityUI.init(content);
 
-    // A mozbrowser iframe contained inside a mozapp iframe should return false
-    // for nsWindowUtils::IsPartOfApp (unless the mozbrowser iframe is itself
-    // also mozapp).  That is, mozapp is transitive down to its children, but
-    // mozbrowser serves as a barrier.
-    //
-    // This is because mozapp iframes have some privileges which we don't want
-    // to extend to untrusted mozbrowser content.
-    //
-    // Get the app manifest from the parent, if our frame has one.
-    let appManifestURL = sendSyncMsg('get-mozapp-manifest-url')[0];
-    let windowUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                             .getInterface(Ci.nsIDOMWindowUtils);
-
-    if (!!appManifestURL) {
-      windowUtils.setIsApp(true);
-      windowUtils.setApp(appManifestURL);
-    } else {
-      windowUtils.setIsApp(false);
-    }
-
     // A cache of the menuitem dom objects keyed by the id we generate
     // and pass to the embedder
     this._ctxHandlers = {};
     // Counter of contextmenu events fired
     this._ctxCounter = 0;
 
     addEventListener('DOMTitleChanged',
                      this._titleChangedHandler.bind(this),
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -24,17 +24,17 @@ using mozilla::dom::TabParent;
 
 namespace {
 
 /**
  * Create an <iframe mozbrowser> owned by the same document as
  * aOpenerFrameElement.
  */
 already_AddRefed<nsHTMLIFrameElement>
-CreateIframe(Element* aOpenerFrameElement)
+CreateIframe(Element* aOpenerFrameElement, const nsAString& aName)
 {
   nsNodeInfoManager *nodeInfoManager =
     aOpenerFrameElement->OwnerDoc()->NodeInfoManager();
 
   nsCOMPtr<nsINodeInfo> nodeInfo =
     nodeInfoManager->GetNodeInfo(nsGkAtoms::iframe,
                                  /* aPrefix = */ nullptr,
                                  kNameSpaceID_XHTML,
@@ -49,16 +49,20 @@ CreateIframe(Element* aOpenerFrameElemen
   // Copy the opener frame's mozapp attribute to the popup frame.
   if (aOpenerFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)) {
     nsAutoString mozapp;
     aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, mozapp);
     popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::mozapp,
                                mozapp, /* aNotify = */ false);
   }
 
+  // Copy the window name onto the iframe.
+  popupFrameElement->SetAttr(kNameSpaceID_None, nsGkAtoms::name,
+                             aName, /* aNotify = */ false);
+
   return popupFrameElement.forget();
 }
 
 /**
  * Dispatch a mozbrowseropenwindow event to the given opener frame element.
  * The "popup iframe" (event.detail.frameElement) will be |aPopupFrameElement|.
  *
  * Returns true iff there were no unexpected failures and the window.open call
@@ -126,17 +130,17 @@ BrowserElementParent::OpenWindowOOP(mozi
                                     const nsAString& aName,
                                     const nsAString& aFeatures)
 {
   // Create an iframe owned by the same document which owns openerFrameElement.
   nsCOMPtr<Element> openerFrameElement =
     do_QueryInterface(aOpenerTabParent->GetOwnerElement());
   NS_ENSURE_TRUE(openerFrameElement, false);
   nsRefPtr<nsHTMLIFrameElement> popupFrameElement =
-    CreateIframe(openerFrameElement);
+    CreateIframe(openerFrameElement, aName);
 
   // Normally an <iframe> element will try to create a frameLoader when the
   // page touches iframe.contentWindow or sets iframe.src.
   //
   // But in our case, we want to delay the creation of the frameLoader until
   // we've verified that the popup has gone through successfully.  If the popup
   // is "blocked" by the embedder, we don't want to load the popup's url.
   //
@@ -184,17 +188,17 @@ BrowserElementParent::OpenWindowInProces
   nsCOMPtr<nsIDOMElement> openerFrameDOMElement;
   topWindow->GetFrameElement(getter_AddRefs(openerFrameDOMElement));
   NS_ENSURE_TRUE(openerFrameDOMElement, false);
 
   nsCOMPtr<Element> openerFrameElement =
     do_QueryInterface(openerFrameDOMElement);
 
   nsRefPtr<nsHTMLIFrameElement> popupFrameElement =
-    CreateIframe(openerFrameElement);
+    CreateIframe(openerFrameElement, aName);
   NS_ENSURE_TRUE(popupFrameElement, false);
 
   nsCAutoString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
   bool dispatchSucceeded =
     DispatchOpenWindowEvent(openerFrameElement, popupFrameElement,
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -152,27 +152,27 @@ function BrowserElementParent(frameLoade
       if (self._isAlive()) {
         return handler.apply(self, arguments);
       }
     }
     self._mm.addMessageListener('browser-element-api:' + msg, checkedHandler);
   }
 
   addMessageListener("hello", this._recvHello);
+  addMessageListener("get-name", this._recvGetName);
   addMessageListener("contextmenu", this._fireCtxMenuEvent);
   addMessageListener("locationchange", this._fireEventFromMsg);
   addMessageListener("loadstart", this._fireEventFromMsg);
   addMessageListener("loadend", this._fireEventFromMsg);
   addMessageListener("titlechange", this._fireEventFromMsg);
   addMessageListener("iconchange", this._fireEventFromMsg);
   addMessageListener("close", this._fireEventFromMsg);
   addMessageListener("securitychange", this._fireEventFromMsg);
   addMessageListener("error", this._fireEventFromMsg);
   addMessageListener("scroll", this._fireEventFromMsg);
-  addMessageListener("get-mozapp-manifest-url", this._sendMozAppManifestURL);
   addMessageListener("keyevent", this._fireKeyEvent);
   addMessageListener("showmodalprompt", this._handleShowModalPrompt);
   addMessageListener('got-screenshot', this._gotDOMRequestResult);
   addMessageListener('got-can-go-back', this._gotDOMRequestResult);
   addMessageListener('got-can-go-forward', this._gotDOMRequestResult);
   addMessageListener('fullscreen-origin-change', this._remoteFullscreenOriginChange);
   addMessageListener('rollback-fullscreen', this._remoteFrameFullscreenReverted);
   addMessageListener('exit-fullscreen', this._exitFullscreen);
@@ -257,16 +257,20 @@ BrowserElementParent.prototype = {
     // that we must do so here, rather than in the BrowserElementParent
     // constructor, because the BrowserElementChild may not be initialized when
     // we run our constructor.
     if (this._window.document.mozHidden) {
       this._ownerVisibilityChange();
     }
   },
 
+  _recvGetName: function(data) {
+    return this._frameElement.getAttribute('name');
+  },
+
   _fireCtxMenuEvent: function(data) {
     let evtName = data.name.substring('browser-element-api:'.length);
     let detail = data.json;
 
     debug('fireCtxMenuEventFromMsg: ' + evtName + ' ' + detail);
     let evt = this._createEvent(evtName, detail);
 
     if (detail.contextmenu) {
@@ -357,20 +361,16 @@ BrowserElementParent.prototype = {
                                             detail: detail });
     }
 
     return new this._window.Event('mozbrowser' + evtName,
                                   { bubbles: true,
                                     cancelable: cancelable });
   },
 
-  _sendMozAppManifestURL: function(data) {
-    return this._frameElement.getAttribute('mozapp');
-  },
-
   /**
    * Kick off a DOMRequest in the child process.
    *
    * We'll fire an event called |msgName| on the child process, passing along
    * an object with a single field, id, containing the ID of this request.
    *
    * We expect the child to pass the ID back to us upon completion of the
    * request; see _gotDOMRequestResult.
--- a/dom/browser-element/mochitest/Makefile.in
+++ b/dom/browser-element/mochitest/Makefile.in
@@ -28,16 +28,22 @@ MOCHITEST_FILES = \
 		browserElement_DataURI.js \
 		test_browserElement_inproc_DataURI.html \
 		browserElement_ErrorSecurity.js \
 		test_browserElement_inproc_ErrorSecurity.html \
 		browserElement_Titlechange.js \
 		test_browserElement_inproc_Titlechange.html \
 		browserElement_TopBarrier.js \
 		test_browserElement_inproc_TopBarrier.html \
+		browserElement_AppWindowNamespace.js \
+		test_browserElement_inproc_AppWindowNamespace.html \
+		file_browserElement_AppWindowNamespace.html \
+		browserElement_BrowserWindowNamespace.js \
+		test_browserElement_inproc_BrowserWindowNamespace.html \
+		file_browserElement_BrowserWindowNamespace.html \
 		browserElement_Iconchange.js \
 		test_browserElement_inproc_Iconchange.html \
 		browserElement_GetScreenshot.js \
 		test_browserElement_inproc_GetScreenshot.html \
 		browserElement_SetVisible.js \
 		test_browserElement_inproc_SetVisible.html \
 		browserElement_SetVisibleFrames.js \
 		test_browserElement_inproc_SetVisibleFrames.html \
@@ -61,16 +67,19 @@ MOCHITEST_FILES = \
 		test_browserElement_inproc_Alert.html \
 		browserElement_AlertInFrame.js \
 		test_browserElement_inproc_AlertInFrame.html \
 		file_browserElement_AlertInFrame.html \
 		file_browserElement_AlertInFrame_Inner.html \
 		browserElement_TargetTop.js \
 		test_browserElement_inproc_TargetTop.html \
 		file_browserElement_TargetTop.html \
+		browserElement_ForwardName.js \
+		test_browserElement_inproc_ForwardName.html \
+		file_browserElement_ForwardName.html \
 		browserElement_PromptCheck.js \
 		test_browserElement_inproc_PromptCheck.html \
 		browserElement_PromptConfirm.js \
 		test_browserElement_inproc_PromptConfirm.html \
 		browserElement_Close.js \
 		test_browserElement_inproc_Close.html \
 		browserElement_CloseFromOpener.js \
 		test_browserElement_inproc_CloseFromOpener.html \
@@ -83,16 +92,20 @@ MOCHITEST_FILES = \
 		test_browserElement_inproc_OpenWindowInFrame.html \
 		file_browserElement_OpenWindowInFrame.html \
 		browserElement_OpenWindowRejected.js \
 		test_browserElement_inproc_OpenWindowRejected.html \
 		file_browserElement_OpenWindowRejected.html \
 		browserElement_OpenWindowDifferentOrigin.js \
 		test_browserElement_inproc_OpenWindowDifferentOrigin.html \
 		file_browserElement_OpenWindowDifferentOrigin.html \
+		browserElement_OpenNamed.js \
+		test_browserElement_inproc_OpenNamed.html \
+		file_browserElement_OpenNamed.html \
+		file_browserElement_OpenNamed2.html \
 		browserElement_SecurityChange.js \
 		test_browserElement_inproc_SecurityChange.html \
 		file_browserElement_SecurityChange.html \
 		browserElement_BackForward.js \
 		test_browserElement_inproc_BackForward.html \
 	        file_bug741717.sjs \
 		browserElement_Reload.js \
 	        file_bug709759.sjs \
@@ -113,37 +126,41 @@ MOCHITEST_FILES = \
 # 774939).
 ifneq ($(OS_ARCH),WINNT) #{
 ifndef MOZ_JAVA_COMPOSITOR #{
 MOCHITEST_FILES += \
 		test_browserElement_oop_LoadEvents.html \
 		test_browserElement_oop_DataURI.html \
 		test_browserElement_oop_ErrorSecurity.html \
 		test_browserElement_oop_Titlechange.html \
+		test_browserElement_oop_AppWindowNamespace.html \
+		test_browserElement_oop_BrowserWindowNamespace.html \
 		test_browserElement_oop_TopBarrier.html \
 		test_browserElement_oop_Iconchange.html \
 		test_browserElement_oop_GetScreenshot.html \
 		test_browserElement_oop_SetVisible.html \
 		test_browserElement_oop_SetVisibleFrames.html \
 		test_browserElement_oop_SetVisibleFrames2.html \
 		test_browserElement_oop_KeyEvents.html \
 		test_browserElement_oop_XFrameOptions.html \
 		test_browserElement_oop_XFrameOptionsDeny.html \
 		test_browserElement_oop_XFrameOptionsSameOrigin.html \
 		test_browserElement_oop_Alert.html \
 		test_browserElement_oop_AlertInFrame.html \
 		test_browserElement_oop_TargetTop.html \
+		test_browserElement_oop_ForwardName.html \
 		test_browserElement_oop_PromptCheck.html \
 		test_browserElement_oop_PromptConfirm.html \
 		test_browserElement_oop_Close.html \
 		test_browserElement_oop_CloseFromOpener.html \
 		test_browserElement_oop_OpenWindow.html \
 		test_browserElement_oop_OpenWindowInFrame.html \
 		test_browserElement_oop_OpenWindowRejected.html \
 		test_browserElement_oop_OpenWindowDifferentOrigin.html \
+		test_browserElement_oop_OpenNamed.html \
 		test_browserElement_oop_SecurityChange.html \
 		test_browserElement_oop_BackForward.html \
 		test_browserElement_oop_Reload.html \
 		test_browserElement_oop_Stop.html \
                 test_browserElement_oop_ContextmenuEvents.html \
 		test_browserElement_oop_SendEvent.html \
 		test_browserElement_oop_ScrollEvent.html \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_AppWindowNamespace.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 780351 - Test that mozapp divides the window name namespace.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  browserElementTestHelpers.setEnabledPref(true);
+  browserElementTestHelpers.addToWhitelist();
+
+  var iframe1 = document.createElement('iframe');
+  iframe1.mozbrowser = true;
+  iframe1.setAttribute('mozapp', 'http://example.org/manifest.webapp');
+
+  // Two mozapp frames for different apps with the same code both do the same
+  // window.open("foo", "bar") call.  We should get two mozbrowseropenwindow
+  // events.
+
+  iframe1.addEventListener('mozbrowseropenwindow', function(e) {
+    ok(true, "Got first mozbrowseropenwindow event.");
+    document.body.appendChild(e.detail.frameElement);
+
+    SimpleTest.executeSoon(function() {
+      var iframe2 = document.createElement('iframe');
+      iframe2.mozbrowser = true;
+      iframe2.setAttribute('mozapp', 'http://example.com/manifest.webapp');
+
+      iframe2.addEventListener('mozbrowseropenwindow', function(e) {
+        ok(true, "Got second mozbrowseropenwindow event.");
+        SimpleTest.finish();
+      });
+
+      document.body.appendChild(iframe2);
+      iframe2.src = 'http://example.com/tests/dom/browser-element/mochitest/file_browserElement_AppWindowNamespace.html';
+    });
+  });
+
+  document.body.appendChild(iframe1);
+  iframe1.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AppWindowNamespace.html';
+}
+
+runTest();
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_BrowserWindowNamespace.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 780351 - Test that mozbrowser does /not/ divide the window name namespace.
+// Multiple mozbrowsers inside the same app are like multiple browser tabs;
+// they share a window name namespace.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  browserElementTestHelpers.setEnabledPref(true);
+  browserElementTestHelpers.addToWhitelist();
+
+  var iframe1 = document.createElement('iframe');
+  iframe1.mozbrowser = true;
+
+  // Two mozbrowser frames with the same code both do the same
+  // window.open("foo", "bar") call.  We should only get one
+  // mozbrowseropenwindow event.
+
+  iframe1.addEventListener('mozbrowseropenwindow', function(e) {
+    ok(true, "Got first mozbrowseropenwindow event.");
+    document.body.appendChild(e.detail.frameElement);
+
+    e.detail.frameElement.addEventListener('mozbrowserlocationchange', function(e) {
+      if (e.detail == "http://example.com/#2") {
+        ok(true, "Got locationchange to http://example.com/#2");
+        SimpleTest.finish();
+      }
+      else {
+        ok(true, "Got locationchange to " + e.detail);
+      }
+    });
+
+    SimpleTest.executeSoon(function() {
+      var iframe2 = document.createElement('iframe');
+      iframe2.mozbrowser = true;
+
+      iframe2.addEventListener('mozbrowseropenwindow', function(e) {
+        ok(false, "Got second mozbrowseropenwindow event.");
+      });
+
+      document.body.appendChild(iframe2);
+      iframe2.src = 'file_browserElement_BrowserWindowNamespace.html#2';
+    });
+  });
+
+  document.body.appendChild(iframe1);
+  iframe1.src = 'file_browserElement_BrowserWindowNamespace.html#1';
+}
+
+runTest();
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_ForwardName.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 781320 - Test that the name in <iframe mozbrowser name="foo"> is
+// forwarded down to remote mozbrowsers.
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  browserElementTestHelpers.setEnabledPref(true);
+  browserElementTestHelpers.addToWhitelist();
+
+  var iframe = document.createElement('iframe');
+  iframe.mozbrowser = true;
+  iframe.setAttribute('name', 'foo');
+
+  iframe.addEventListener("mozbrowseropenwindow", function(e) {
+    ok(false, 'Got mozbrowseropenwindow, but should not have.');
+  });
+
+  iframe.addEventListener('mozbrowserlocationchange', function(e) {
+    ok(true, "Got locationchange to " + e.detail);
+    if (e.detail.endsWith("ForwardName.html#finish")) {
+      SimpleTest.finish();
+    }
+  });
+
+  // The file sends us messages via alert() that start with "success:" or
+  // "failure:".
+  iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
+    ok(e.detail.message.startsWith('success:'), e.detail.message);
+  });
+
+  document.body.appendChild(iframe);
+
+  // This file does window.open('file_browserElement_ForwardName.html#finish',
+  // 'foo');  That should open in the curent window, because the window should
+  // be named foo.
+  iframe.src = 'file_browserElement_ForwardName.html';
+}
+
+runTest();
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_OpenNamed.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 742944 - In <iframe mozbrowser>, test that if we call window.open twice
+// with the same name, we get only one mozbrowseropenwindow event.
+
+"use strict";
+SimpleTest.waitForExplicitFinish();
+
+var iframe;
+var popupFrame;
+function runTest() {
+  browserElementTestHelpers.setEnabledPref(true);
+  browserElementTestHelpers.addToWhitelist();
+
+  iframe = document.createElement('iframe');
+  iframe.mozbrowser = true;
+
+  var gotPopup = false;
+  iframe.addEventListener('mozbrowseropenwindow', function(e) {
+    is(gotPopup, false, 'Should get just one popup.');
+    gotPopup = true;
+    popupFrame = e.detail.frameElement;
+    is(popupFrame.getAttribute('name'), 'OpenNamed');
+
+    // Called when file_browserElement_OpenNamed2.html loads into popupFrame.
+    popupFrame.addEventListener('mozbrowsershowmodalprompt', function promptlistener(e) {
+      popupFrame.removeEventListener('mozbrowsershowmodalprompt', promptlistener);
+
+      ok(gotPopup, 'Got openwindow event before showmodalprompt event.');
+      is(e.detail.message, 'success: loaded');
+      SimpleTest.executeSoon(test2);
+    });
+
+    document.body.appendChild(popupFrame);
+  });
+
+  // OpenNamed.html will call
+  //
+  //    window.open('file_browserElement_OpenNamed2.html', 'OpenNamed').
+  //
+  // Once that popup loads, we reload OpenNamed.html.  That will call
+  // window.open again, but we shouldn't get another openwindow event, because
+  // we're opening into the same named window.
+  iframe.src = 'file_browserElement_OpenNamed.html';
+  document.body.appendChild(iframe);
+}
+
+function test2() {
+  popupFrame.addEventListener('mozbrowsershowmodalprompt', function(e) {
+    is(e.detail.message, 'success: loaded');
+    SimpleTest.finish();
+  });
+
+  iframe.src = 'file_browserElement_OpenNamed.html?test2';
+}
+
+runTest();
--- a/dom/browser-element/mochitest/createNewTest.py
+++ b/dom/browser-element/mochitest/createNewTest.py
@@ -54,17 +54,17 @@ def print_fill(s):
     print(textwrap.fill(textwrap.dedent(s)))
 
 def add_to_makefile(filenames):
     """Add a list of filenames to this directory's Makefile.in, then open
     $EDITOR and let the user move the filenames to their appropriate places in
     the file.
 
     """
-    lines_to_write = ['', '# MOVE THESE:'] + [n + ' \\' for n in filenames]
+    lines_to_write = [''] + ['\t\t%s \\' % n for n in filenames]
     with open('Makefile.in', 'a') as f:
         f.write('\n'.join(lines_to_write))
 
     if 'EDITOR' not in os.environ or not os.environ['EDITOR']:
         print_fill("""\
             Now open Makefile.in and move the filenames to their correct places.")
             (Define $EDITOR and I'll open your editor for you next time.)""")
         return
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_AppWindowNamespace.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<script>
+window.open("http://example.com", "foo");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_BrowserWindowNamespace.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<script>
+window.open("http://example.com/" + location.hash, "foo");
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_ForwardName.html
@@ -0,0 +1,15 @@
+<html>
+<body>
+<script>
+
+if (window.name == 'foo') {
+  alert("success:window.name == 'foo'");
+}
+else {
+  alert("failure:window.name == '" + window.name + "', expected 'foo'");
+}
+
+window.open('file_browserElement_ForwardName.html#finish', 'foo');
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenNamed.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<script>
+window.open('file_browserElement_OpenNamed2.html', 'OpenNamed');
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/file_browserElement_OpenNamed2.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<script>
+alert('success: loaded');
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_AppWindowNamespace.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 780351</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AppWindowNamespace.js">
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_BrowserWindowNamespace.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 780351</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BrowserWindowNamespace.js">
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_ForwardName.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 781320</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ForwardName.js">
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_OpenNamed.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test of browser element.</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenNamed.js">
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_AppWindowNamespace.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 780351</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_AppWindowNamespace.js">
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_BrowserWindowNamespace.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 780351</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_BrowserWindowNamespace.js">
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_ForwardName.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Bug 781320</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_ForwardName.js">
+</script>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_OpenNamed.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test of browser element.</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="application/javascript;version=1.7" src="browserElement_OpenNamed.js">
+</script>
+</body>
+</html>
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -842,17 +842,17 @@ public:
 
     nsRefPtr<nsIDOMDeviceStorageStat> domstat = new nsDOMDeviceStorageStat(mFreeBytes, mTotalBytes);
 
     jsval result = InterfaceToJsval(mRequest->GetOwner(),
 				    domstat,
 				    &NS_GET_IID(nsIDOMDeviceStorageStat));
 
     mRequest->FireSuccess(result);
-    mRequest = nsnull;
+    mRequest = nullptr;
     return NS_OK;
   }
 
 private:
   PRInt64 mFreeBytes, mTotalBytes;
   nsRefPtr<DOMRequest> mRequest;
 };
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -784,17 +784,17 @@ IndexedDatabaseManager::EnsureOriginIsIn
   // Now tell SQLite to start tracking this pattern for content.
   nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
 
   if (aPrivilege != Chrome) {
     rv = ss->SetQuotaForFilenamePattern(pattern,
                                         GetIndexedDBQuotaMB() * 1024 * 1024,
-                                        mQuotaCallbackSingleton, nsnull);
+                                        mQuotaCallbackSingleton, nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // We need to see if there are any files in the directory already. If they
   // are database files then we need to create file managers for them and also
   // tell SQLite about all of them.
 
   nsAutoTArray<nsString, 20> subdirsToProcess;
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -33,19 +33,18 @@ interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMBlob;
 interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 interface nsIDOMClientRect;
-interface mozIDOMApplication;
 
-[scriptable, uuid(97548ee0-9def-421a-ab2a-c6c98efa9a3c)]
+[scriptable, uuid(5fc61d7b-a303-4f34-adfe-b7828675ba45)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1181,30 +1180,13 @@ interface nsIDOMWindowUtils : nsISupport
    * Set the scrollport size for the purposes of clamping scroll positions for
    * the root scroll frame of this document to be (aWidth,aHeight) in CSS pixels.
    *
    * The caller of this method must have UniversalXPConnect privileges.
    */
   void setScrollPositionClampingScrollPortSize(in float aWidth, in float aHeight);
 
   /**
-   * Mark if the window is an application window or not.
-   * This should only be set for top-level mozApp or mozBrowser frames.
-   * It should not be set for other frames unless you want a frame (and its
-   * children) to have a different value for IsPartOfApp than the frame's
-   * parent.
+   * Prevent this window (and any child windows) from displaying any further
+   * dialogs (e.g. window.alert()).
    */
-  void setIsApp(in boolean value);
-
-  /**
-   * Associate the window with an application by passing the URL of the
-   * application's manifest.
-   *
-   * This method will throw an exception if the manifest URL isn't a valid URL
-   * or isn't the manifest URL of an installed application.
-   */
-  void setApp(in DOMString manifestURL);
-  /**
-    * Retrieves the Application object associated to this window.
-    * Can be null if |setApp()| has not been called.
-    */
-  mozIDOMApplication getApp();
+  void preventFurtherDialogs();
 };
--- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
+++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
@@ -150,16 +150,22 @@ interface nsIWebGLExtensionCompressedTex
 {
     /* Compressed Texture Formats */
     const WebGLenum COMPRESSED_RGB_S3TC_DXT1_EXT        = 0x83F0;
     const WebGLenum COMPRESSED_RGBA_S3TC_DXT1_EXT       = 0x83F1;
     const WebGLenum COMPRESSED_RGBA_S3TC_DXT3_EXT       = 0x83F2;
     const WebGLenum COMPRESSED_RGBA_S3TC_DXT5_EXT       = 0x83F3;
 };
 
+[scriptable, builtinclass, uuid(ef36f000-c1b2-11e1-afa7-0800200c9a66)]
+interface nsIWebGLExtensionDepthTexture : nsIWebGLExtension
+{
+  const WebGLenum UNSIGNED_INT_24_8_WEBGL = 0x84FA;
+};
+
 [scriptable, builtinclass, uuid(a1fdfb76-6a08-4a1a-b0c9-d92ef3357cb9)]
 interface nsIDOMWebGLRenderingContext : nsISupports
 {
   //
   //  CONSTANTS
   //
 
   /* ClearBufferMask */
--- a/dom/ipc/PermissionMessageUtils.h
+++ b/dom/ipc/PermissionMessageUtils.h
@@ -11,17 +11,17 @@
 #include "nsIPrincipal.h"
 
 namespace IPC {
 
 class Principal {
   friend struct ParamTraits<Principal>;
 
 public:
-  Principal() : mPrincipal(nsnull) {}
+  Principal() : mPrincipal(nullptr) {}
   Principal(nsIPrincipal* aPrincipal) : mPrincipal(aPrincipal) {}
   operator nsIPrincipal*() const { return mPrincipal.get(); }
 
 private:
   // Unimplemented
   Principal& operator=(Principal&);
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -163,25 +163,23 @@ SystemMessageManager.prototype = {
 
     this._dispatchMessage(msg.type, this._handlers[msg.type], msg.msg);
   },
 
   // nsIDOMGlobalPropertyInitializer implementation.
   init: function sysMessMgr_init(aWindow) {
     debug("init");
     this.initHelper(aWindow, ["SystemMessageManager:Message"]);
-    this._uri = aWindow.document.nodePrincipal.URI.spec;
-    let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Components.interfaces.nsIDOMWindowUtils);
+
+    let principal = aWindow.document.nodePrincipal;
+    this._uri = principal.URI.spec;
 
-    // Get the manifest url is this is an installed app.
-    this._manifest = null;
-    let app = utils.getApp();
-    if (app)
-      this._manifest = app.manifestURL;
+    let appsService = Cc["@mozilla.org/AppsService;1"]
+                        .getService(Ci.nsIAppsService);
+    this._manifest = appsService.getManifestURLByLocalId(principal.appId);
   },
 
   classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMNavigatorSystemMessages,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 
   classInfo: XPCOMUtils.generateCI({classID: Components.ID("{bc076ea0-609b-4d8f-83d7-5af7cbdc3bb2}"),
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -649,16 +649,22 @@ PluginInstanceParent::RecvShow(const NPR
         gfxRect ur(updatedRect.left, updatedRect.top,
                    updatedRect.right - updatedRect.left,
                    updatedRect.bottom - updatedRect.top);
         surface->MarkDirty(ur);
         surface->Flush();
     }
 
     mFrontSurface = surface;
+    if (!surface) {
+      ImageContainer* container = GetImageContainer();
+      if (container) {
+        container->SetCurrentImage(nullptr);
+      }
+    }
     RecvNPN_InvalidateRect(updatedRect);
 
     PLUGIN_LOG_DEBUG(("   (RecvShow invalidated for surface %p)",
                       mFrontSurface.get()));
 
     return true;
 }
 
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -1,19 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Hal.h"
 #include "PowerManager.h"
 #include "WakeLock.h"
-#include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMWakeLockListener.h"
+#include "nsIDocument.h"
+#include "nsIPermissionManager.h"
 #include "nsIPowerManagerService.h"
 #include "nsIPrincipal.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDOMError.h"
 
 DOMCI_DATA(MozPowerManager, mozilla::dom::power::PowerManager)
 
@@ -52,93 +53,61 @@ PowerManager::Shutdown()
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   // Remove ourself from the global notification list.
   pmService->RemoveWakeLockListener(this);
   return NS_OK;
 }
 
-bool
-PowerManager::CheckPermission()
-{
-  if (nsContentUtils::IsCallerChrome()) {
-    return true;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-  NS_ENSURE_TRUE(win, false);
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
-  NS_ENSURE_TRUE(doc, false);
-
-  nsCOMPtr<nsIURI> uri;
-  doc->NodePrincipal()->GetURI(getter_AddRefs(uri));
-
-  if (!nsContentUtils::URIIsChromeOrInPref(uri, "dom.power.whitelist")) {
-    return false;
-  }
-
-  return true;
-}
-
 NS_IMETHODIMP
 PowerManager::Reboot()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->Reboot();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::PowerOff()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->PowerOff();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   // already added? bail out.
   if (mListeners.Contains(aListener))
     return NS_OK;
 
   mListeners.AppendElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::RemoveWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   mListeners.RemoveElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetWakeLockState(const nsAString &aTopic, nsAString &aState)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   return pmService->GetWakeLockState(aTopic, aState);
 }
 
 NS_IMETHODIMP
@@ -158,74 +127,81 @@ PowerManager::Callback(const nsAString &
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenEnabled(bool *aEnabled)
 {
-  if (!CheckPermission()) {
-    *aEnabled = true;
-    return NS_OK;
-  }
-
   *aEnabled = hal::GetScreenEnabled();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenEnabled(bool aEnabled)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
-  // TODO bug 707589: When the screen's state changes, all visible windows
-  // should fire a visibility change event.
   hal::SetScreenEnabled(aEnabled);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenBrightness(double *aBrightness)
 {
-  if (!CheckPermission()) {
-    *aBrightness = 1;
-    return NS_OK;
-  }
-
   *aBrightness = hal::GetScreenBrightness();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenBrightness(double aBrightness)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   NS_ENSURE_TRUE(0 <= aBrightness && aBrightness <= 1, NS_ERROR_INVALID_ARG);
   hal::SetScreenBrightness(aBrightness);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetCpuSleepAllowed(bool *aAllowed)
 {
-  if (!CheckPermission()) {
-    *aAllowed = true;
-    return NS_OK;
-  }
-
   *aAllowed = hal::GetCpuSleepAllowed();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetCpuSleepAllowed(bool aAllowed)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   hal::SetCpuSleepAllowed(aAllowed);
   return NS_OK;
 }
 
+already_AddRefed<PowerManager>
+PowerManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
+{
+  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
+    aWindow :
+    aWindow->GetCurrentInnerWindow();
+
+  // Need the document for security check.
+  nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
+  NS_ENSURE_TRUE(document, nullptr);
+
+  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
+
+  nsCOMPtr<nsIPermissionManager> permMgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(permMgr, nullptr);
+
+  PRUint32 permission = nsIPermissionManager::DENY_ACTION;
+  permMgr->TestPermissionFromPrincipal(principal, "power", &permission);
+
+  if (permission != nsIPermissionManager::ALLOW_ACTION) {
+    return nullptr;
+  }
+
+  nsRefPtr<PowerManager> powerManager = new PowerManager();
+  powerManager->Init(aWindow);
+
+  return powerManager.forget();
+}
+
 } // power
 } // dom
 } // mozilla
--- a/dom/power/PowerManager.h
+++ b/dom/power/PowerManager.h
@@ -7,16 +7,18 @@
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsIDOMPowerManager.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIDOMWindow.h"
 #include "nsWeakReference.h"
 
+class nsPIDOMWindow;
+
 namespace mozilla {
 namespace dom {
 namespace power {
 
 class PowerManager
   : public nsIDOMMozPowerManager
   , public nsIDOMMozWakeLockListener
 {
@@ -26,18 +28,20 @@ public:
   NS_DECL_NSIDOMMOZWAKELOCKLISTENER
 
   PowerManager() {};
   virtual ~PowerManager() {};
 
   nsresult Init(nsIDOMWindow *aWindow);
   nsresult Shutdown();
 
+  static already_AddRefed<PowerManager>
+  CheckPermissionAndCreateInstance(nsPIDOMWindow*);
+
 private:
-  bool CheckPermission();
 
   nsWeakPtr mWindow;
   nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
 };
 
 } // namespace power
 } // namespace dom
 } // namespace mozilla
--- a/dom/power/test/browser_bug697132.js
+++ b/dom/power/test/browser_bug697132.js
@@ -1,24 +1,27 @@
+/* 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";
 
 waitForExplicitFinish();
 
-let kPrefNode = "dom.power.whitelist";
-let kPageSource1 = "data:text/html,1";
-let kPageSource2 = "data:text/html,2";
+let kUrlSource = "http://mochi.test:8888/";
+let kDataSource = "data:text/html,";
 
 let gOldPref;
 let gWin, gWin1, gWin2;
 let gTab, gTab1, gTab2;
 let gLock, gLock1, gLock2;
 let gCurStepIndex = -1;
 let gSteps = [
   function basicWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       gLock = nav.requestWakeLock("test");
@@ -46,17 +49,17 @@ let gSteps = [
       }
 
       gBrowser.removeTab(gTab);
 
       executeSoon(runNextStep);
     }, true);
   },
   function multiWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       let count = 0;
@@ -95,19 +98,19 @@ let gSteps = [
       gLock1.unlock();
       isnot(power.getWakeLockState("test"), "unlocked",
             "topic is locked");
 
       gLock2.unlock();
     }, true);
   },
   function crossTabWakeLock1() {
-    gTab1 = gBrowser.addTab(kPageSource1);
+    gTab1 = gBrowser.addTab(kUrlSource);
     gWin1 = gBrowser.getBrowserForTab(gTab1).contentWindow;
-    gTab2 = gBrowser.addTab(kPageSource1);
+    gTab2 = gBrowser.addTab(kUrlSource);
     gWin2 = gBrowser.getBrowserForTab(gTab2).contentWindow;
 
     gBrowser.selectedTab = gTab1;
     let browser = gBrowser.getBrowserForTab(gTab2);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       gLock2 = gWin2.navigator.requestWakeLock("test");
@@ -133,17 +136,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock3() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock4() {
@@ -161,17 +164,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock6() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock7() {
@@ -214,23 +217,17 @@ let gSteps = [
   },
 ];
 
 function runNextStep() {
   gCurStepIndex++;
   if (gCurStepIndex < gSteps.length) {
     gSteps[gCurStepIndex]();
   } else {
-    Services.prefs.setCharPref(kPrefNode, gOldPref);
+    SpecialPowers.removePermission("power", kUrlSource);
     finish();
   }
 }
 
 function test() {
-  try {
-    gOldPref = Services.prefs.getCharPref(kPrefNode);
-  } catch (e) {
-    gOldPref = "";
-  }
-  // data url inherits its parent's principal, which is |about:| here.
-  Services.prefs.setCharPref(kPrefNode, "about:");
+  SpecialPowers.addPermission("power", true, kUrlSource);
   runNextStep();
 }
--- a/dom/power/test/test_power_basics.html
+++ b/dom/power/test/test_power_basics.html
@@ -11,12 +11,24 @@
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Power API **/
 
 ok('mozPower' in navigator, "navigator.mozPower should exist");
 
+/** Test permission **/
+
+SpecialPowers.removePermission("power", document);
+
+power = navigator.mozPower;
+ok(!power, "Shouldn't be able to access power manager without permission.");
+
+SpecialPowers.addPermission("power", true, document);
+
+power = navigator.mozPower;
+ok(power, "Shouldn be able to access power manager with permission.");
+
 </script>
 </pre>
 </body>
 </html>
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -1890,17 +1890,17 @@ StorageNotifierRunnable::Run()
 
 void
 nsDOMStorage2::BroadcastChangeNotification(const nsSubstring &aKey,
                                            const nsSubstring &aOldValue,
                                            const nsSubstring &aNewValue)
 {
   nsresult rv;
   nsCOMPtr<nsIDOMEvent> domEvent;
-  NS_NewDOMStorageEvent(getter_AddRefs(domEvent), nsnull, nsnull);
+  NS_NewDOMStorageEvent(getter_AddRefs(domEvent), nullptr, nullptr);
   nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(domEvent);
   rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"),
                                false,
                                false,
                                aKey,
                                aOldValue,
                                aNewValue,
                                mDocumentURI,
--- a/dom/system/gonk/AutoMounter.cpp
+++ b/dom/system/gonk/AutoMounter.cpp
@@ -230,27 +230,40 @@ public:
       mAutoVolume[volIndex]->UnregisterObserver(&mVolumeEventObserver);
     }
     Volume::UnregisterObserver(&mVolumeEventObserver);
     VolumeManager::UnregisterStateObserver(&mVolumeManagerStateObserver);
   }
 
   void UpdateState();
 
+  const char *ModeStr(int32_t aMode)
+  {
+    switch (aMode) {
+      case AUTOMOUNTER_DISABLE:                 return "Disable";
+      case AUTOMOUNTER_ENABLE:                  return "Enable";
+      case AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED:  return "DisableWhenUnplugged";
+    }
+    return "??? Unknown ???";
+  }
+
   void SetMode(int32_t aMode)
   {
     if ((aMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) &&
         (mMode == AUTOMOUNTER_DISABLE)) {
       // If it's already disabled, then leave it as disabled.
       // AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED implies "enabled until unplugged"
       aMode = AUTOMOUNTER_DISABLE;
     }
-    mMode = aMode;
-    DBG("Calling UpdateState due to mode set to %d", mMode);
-    UpdateState();
+    if (aMode != mMode) {
+      LOG("Changing mode from '%s' to '%s'", ModeStr(mMode), ModeStr(aMode));
+      mMode = aMode;
+      DBG("Calling UpdateState due to mode set to %d", mMode);
+      UpdateState();
+    }
   }
 
 private:
 
   AutoVolumeEventObserver         mVolumeEventObserver;
   AutoVolumeManagerStateObserver  mVolumeManagerStateObserver;
   RefPtr<VolumeResponseCallback>  mResponseCallback;
   int32_t                         mMode;
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -62,27 +62,30 @@ AutoMounterSetting::AutoMounterSetting()
   }
   nsresult rv;
   rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false);
   if (NS_FAILED(rv)) {
     ERR("AddObserver failed");
     return;
   }
 
-  // Get the initial value of the setting.
+  // Force ums.mode to be 0 initially. We do this because settings are persisted.
+  // We don't want UMS to be enabled until such time as the phone is unlocked,
+  // and gaia/apps/system/js/storage.js takes care of detecting when the phone
+  // becomes unlocked and changes ums.mode appropriately.
   nsCOMPtr<nsISettingsService> settingsService =
     do_GetService("@mozilla.org/settingsService;1");
   if (!settingsService) {
     ERR("Failed to get settingsLock service!");
     return;
   }
   nsCOMPtr<nsISettingsServiceLock> lock;
   settingsService->GetLock(getter_AddRefs(lock));
   nsCOMPtr<nsISettingsServiceCallback> callback = new SettingsServiceCallback();
-  lock->Get(UMS_MODE, callback);
+  lock->Set(UMS_MODE, INT_TO_JSVAL(AUTOMOUNTER_DISABLE), callback);
 }
 
 AutoMounterSetting::~AutoMounterSetting()
 {
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (observerService) {
     observerService->RemoveObserver(this, MOZSETTINGS_CHANGED);
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -536,17 +536,17 @@ RadioInterfaceLayer.prototype = {
     if (!this.dataCallSettings["enabled"]) {
       return;
     }
 
     let isRegistered =
       newInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED &&
       (!newInfo.roaming || this._isDataRoamingEnabled());
     let haveDataConnection =
-      newInfo.type != GECKO_MOBILE_CONNECTION_STATE_UNKNOWN;
+      newInfo.type != RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN;
 
     if (isRegistered && haveDataConnection) {
       debug("Radio is ready for data connection.");
       this.updateRILNetworkInterface();
     }
   },
 
   handleSignalStrengthChange: function handleSignalStrengthChange(message) {
@@ -675,18 +675,19 @@ RadioInterfaceLayer.prototype = {
       case nsIRadioInterfaceLayer.CALL_STATE_INCOMING:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
         debug("Incoming call, put audio system into PHONE_STATE_RINGTONE: "
               + gAudioManager.phoneState);
         break;
       case nsIRadioInterfaceLayer.CALL_STATE_DIALING: // Fall through...
       case nsIRadioInterfaceLayer.CALL_STATE_CONNECTED:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
-        gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
-                                     nsIAudioManager.FORCE_NONE);
+        let force = this.speakerEnabled ? nsIAudioManager.FORCE_SPEAKER
+                                        : nsIAudioManager.FORCE_NONE;
+        gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION, force);
         debug("Active call, put audio system into PHONE_STATE_IN_CALL: "
               + gAudioManager.phoneState);
         break;
     }
   },
 
   /**
    * Handle call state changes by updating our current state and the audio
@@ -1759,30 +1760,46 @@ let RILNetworkInterface = {
   timer: null,
 
   type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
 
   name: null,
 
   dhcp: false,
 
+  ip: null,
+
+  netmask: null,
+
+  broadcast: null,
+
+  dns1: null,
+
+  dns2: null,
+
   httpProxyHost: null,
 
   httpProxyPort: null,
 
   // nsIRILDataCallback
 
   dataCallStateChanged: function dataCallStateChanged(datacall) {
     debug("Data call ID: " + datacall.cid + ", interface name: " + datacall.ifname);
     if (this.connecting &&
         (datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTING ||
          datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED)) {
       this.connecting = false;
       this.cid = datacall.cid;
       this.name = datacall.ifname;
+      this.ip = datacall.ip;
+      this.netmask = datacall.netmask;
+      this.broadcast = datacall.broadcast;
+      this.gateway = datacall.gw;
+      this.dns1 = datacall.dns[0];
+      this.dns2 = datacall.dns[1];
       if (!this.registeredAsNetworkInterface) {
         let networkManager = Cc["@mozilla.org/network/manager;1"]
                                .getService(Ci.nsINetworkManager);
         networkManager.registerNetworkInterface(this);
         this.registeredAsNetworkInterface = true;
       }
     }
     if (this.cid != datacall.cid) {
--- a/dom/system/gonk/Volume.cpp
+++ b/dom/system/gonk/Volume.cpp
@@ -61,19 +61,25 @@ Volume::SetMediaPresent(bool aMediaPrese
 }
 
 void
 Volume::SetState(Volume::STATE aNewState)
 {
   if (aNewState == mState) {
     return;
   }
-  LOG("Volume %s: changing state from %s to %s (%d observers)",
-      NameStr(), StateStr(mState),
-      StateStr(aNewState), mEventObserverList.Length());
+  if (aNewState == nsIVolume::STATE_MOUNTED) {
+    LOG("Volume %s: changing state from %s to %s @ '%s' (%d observers)",
+        NameStr(), StateStr(mState),
+        StateStr(aNewState), mMountPoint.get(), mEventObserverList.Length());
+  } else {
+    LOG("Volume %s: changing state from %s to %s (%d observers)",
+        NameStr(), StateStr(mState),
+        StateStr(aNewState), mEventObserverList.Length());
+  }
 
   if (aNewState == nsIVolume::STATE_NOMEDIA) {
     // Cover the startup case where we don't get insertion/removal events
     mMediaPresent = false;
   }
   mState = aNewState;
   mEventObserverList.Broadcast(this);
 }
--- a/dom/system/gonk/nsINetworkManager.idl
+++ b/dom/system/gonk/nsINetworkManager.idl
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 /**
  * Information about networks that is exposed to network manager API consumers.
  */
-[scriptable, uuid(57b56c6f-4c3f-4c55-bf1b-e5af22407931)]
+[scriptable, uuid(49cc227c-3fe7-40a2-bdb5-55e9af797fde)]
 interface nsINetworkInterface : nsISupports
 {
   const long NETWORK_STATE_UNKNOWN = -1;
   const long NETWORK_STATE_CONNECTING = 0;
   const long NETWORK_STATE_CONNECTED = 1;
   const long NETWORK_STATE_SUSPENDED = 2;
   const long NETWORK_STATE_DISCONNECTING = 3;
   const long NETWORK_STATE_DISCONNECTED = 4;
@@ -40,16 +40,46 @@ interface nsINetworkInterface : nsISuppo
   readonly attribute DOMString name;
 
   /**
    * Indicates whether DHCP should be run when the interface connects.
    */
   readonly attribute boolean dhcp;
 
   /**
+   * IP Address
+   */
+  readonly attribute DOMString ip;
+
+  /**
+   * Netmask
+   */
+  readonly attribute DOMString netmask;
+
+  /**
+   * Broadcast
+   */
+  readonly attribute DOMString broadcast;
+
+  /**
+   * Default gateway
+   */
+  readonly attribute DOMString gateway;
+
+  /**
+   * Primary DNS address
+   */
+  readonly attribute DOMString dns1;
+
+  /**
+   * Secondary DNS address
+   */
+  readonly attribute DOMString dns2;
+
+  /**
    * The host name of the http proxy server.
    */
   readonly attribute DOMString httpProxyHost;
 
   /*
    * The port number of the http proxy server. 
    */
   readonly attribute long httpProxyPort;
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -70,27 +70,32 @@ interface nsIRILVoicemailCallback : nsIS
    * Called when a voicemail notification has been received by the network.
    *
    * @param status
    *        The new voicemail status
    */
   void voicemailNotification(in nsIDOMMozVoicemailStatus status);
 };
 
-[scriptable, uuid(8a711703-1ee5-4675-9d9a-0b188e944cfe)]
+[scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)]
 interface nsIRILDataCallInfo : nsISupports
 {
   /**
    * Current data call state, one of the
    * nsINetworkInterface::NETWORK_STATE_* constants.
    */
   readonly attribute unsigned long state;
   readonly attribute AString cid;
   readonly attribute AString apn;
   readonly attribute AString ifname;
+  readonly attribute AString ip;
+  readonly attribute AString netmask;
+  readonly attribute AString broadcast;
+  readonly attribute AString gw;
+  readonly attribute jsval dns;
 };
 
 [scriptable, uuid(5bcac053-c245-46f0-bb45-d0039bfb89f5)]
 interface nsIRILDataCallback : nsISupports
 {
   /**
    * Notified when a data call changes state.
    *
--- a/dom/system/gonk/nsVolumeService.cpp
+++ b/dom/system/gonk/nsVolumeService.cpp
@@ -148,16 +148,23 @@ void nsVolumeService::UpdateVolume(const
     // Nothing has really changed. Don't bother telling anybody.
     return;
   }
   vol->Set(aVolume);
   nsCOMPtr<nsIObserverService> obs = GetObserverService();
   if (!obs) {
     return;
   }
+  if (aVolume->State() == nsIVolume::STATE_MOUNTED) {
+    LOG("UpdateVolume: '%s' state %s @ '%s'",
+        aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPointStr());
+  } else {
+    LOG("UpdateVolume: '%s' state %s",
+        aVolume->NameStr(), aVolume->StateStr());
+  }
   nsString stateStr(NS_ConvertUTF8toUTF16(vol->StateStr()));
   obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
 }
 
 /***************************************************************************
 * The UpdateVolumeRunnable creates an nsVolume and updates the main thread
 * data structure while running on the main thread.
 */
@@ -168,17 +175,17 @@ public:
     : mVolume(new nsVolume(aVolume))
   {
     MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    LOG("UpdateVolumeRunnable::Run '%s' state %s",
+    DBG("UpdateVolumeRunnable::Run '%s' state %s",
         mVolume->NameStr(), mVolume->StateStr());
 
     nsCOMPtr<nsIVolumeService> ivs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
     if (!ivs) {
       return NS_OK;
     }
     nsCOMPtr<nsVolumeService> vs(do_QueryInterface(ivs));
     if (!vs) {
@@ -191,16 +198,16 @@ public:
 
 private:
   nsRefPtr<nsVolume>  mVolume;
 };
 
 //static
 void nsVolumeService::UpdateVolumeIOThread(const Volume *aVolume)
 {
-  LOG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s'",
+  DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s'",
       aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get());
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   NS_DispatchToMainThread(new UpdateVolumeRunnable(aVolume));
 }
 
 } // system
 } // mozilla
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -48,24 +48,24 @@ const UINT8_SIZE  = 1;
 const UINT16_SIZE = 2;
 const UINT32_SIZE = 4;
 const PARCEL_SIZE_SIZE = UINT32_SIZE;
 
 const PDU_HEX_OCTET_SIZE = 4;
 
 const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
 
-let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = false;
-let RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = false;
-// This flag defaults to true since on RIL v6 and later, we get the
-// version number via the UNSOLICITED_RIL_CONNECTED parcel.
-let RILQUIRKS_V5_LEGACY = true;
-let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = false;
-let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = false;
-let RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = false;
+let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = libcutils.property_get("ro.moz.ril.callstate_extra_int");
+let RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = libcutils.property_get("ro.moz.ril.callstate_down_is_up");
+// This may change at runtime since in RIL v6 and later, we get the version
+// number via the UNSOLICITED_RIL_CONNECTED parcel.
+let RILQUIRKS_V5_LEGACY = libcutils.property_get("ro.moz.ril.v5_legacy");
+let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = libcutils.property_get("ro.moz.ril.dial_emergency_call");
+let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = libcutils.property_get("ro.moz.ril.emergency_by_default");
+let RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = libcutils.property_get("ro.moz.ril.simstate_extra_field");
 
 // Marker object.
 let PENDING_NETWORK_TYPE = {};
 
 /**
  * This object contains helpers buffering incoming data & deconstructing it
  * into parcels as well as buffering outgoing data & constructing parcels.
  * For that it maintains two buffers and corresponding uint8 views, indexes.
@@ -686,81 +686,16 @@ let RIL = {
   set muted(val) {
     val = Boolean(val);
     if (this._muted != val) {
       this.setMute(val);
       this._muted = val;
     }
   },
 
-
-  /**
-   * Set quirk flags based on the RIL model detected. Note that this
-   * requires the RIL being "warmed up" first, which happens when on
-   * an incoming or outgoing voice call or data call.
-   */
-  rilQuirksInitialized: false,
-  initRILQuirks: function initRILQuirks() {
-    if (this.rilQuirksInitialized) {
-      return;
-    }
-
-    let ril_impl = libcutils.property_get("gsm.version.ril-impl");
-    if (DEBUG) debug("Detected RIL implementation " + ril_impl);
-    switch (ril_impl) {
-      case "Samsung RIL(IPC) v2.0":
-        // The Samsung Galaxy S2 I-9100 radio sends an extra Uint32 in the
-        // call state.
-        let model_id = libcutils.property_get("ril.model_id");
-        if (DEBUG) debug("Detected RIL model " + model_id);
-        if (!model_id) {
-          // On some RIL models, the RIL has to be "warmed up" for us to read this property.
-          // It apparently isn't warmed up yet, going to try again later.
-          if (DEBUG) debug("Could not detect correct model_id. Going to try later.");
-          return;
-        }
-        if (model_id == "I9100") {
-          if (DEBUG) {
-            debug("Detected I9100, enabling " +
-                  "RILQUIRKS_CALLSTATE_EXTRA_UINT32, " +
-                  "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP, " +
-                  "RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL.");
-          }
-          RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true;
-          RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true;
-          RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = true;
-        }
-        if (model_id == "I9023" || model_id == "I9020") {
-          if (DEBUG) {
-            debug("Detected I9020/I9023, enabling " +
-                  "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP");
-          }
-          RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true;
-        }
-        break;
-      case "Qualcomm RIL 1.0":
-        let product_model = libcutils.property_get("ro.product.model");
-        if (DEBUG) debug("Detected product model " + product_model);
-        if (product_model == "otoro1") {
-          if (DEBUG) debug("Enabling RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS.");
-          RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = true;
-        }
-        if (DEBUG) {
-          debug("Detected Qualcomm RIL 1.0, " +
-                "disabling RILQUIRKS_V5_LEGACY and " +
-                "enabling RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE.");
-        }
-        RILQUIRKS_V5_LEGACY = false;
-        RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = true;
-        break;
-    }
-
-    this.rilQuirksInitialized = true;
-  },
-
   /**
    * Parse an integer from a string, falling back to a default value
    * if the the provided value is not a string or does not contain a valid
    * number.
    *
    * @param string
    *        String to be parsed.
    * @param defaultValue
@@ -2256,18 +2191,16 @@ let RIL = {
       changed = true;
       curState.radioTech = radioTech;
       curState.type = GECKO_RADIO_TECH[radioTech] || null;
     }
     return changed;
   },
 
   _processVoiceRegistrationState: function _processVoiceRegistrationState(state) {
-    this.initRILQuirks();
-
     let rs = this.voiceRegistrationState;
     let stateChanged = this._processCREG(rs, state);
     if (stateChanged && rs.connected) {
       RIL.getSMSCAddress();
     }
 
     let cell = this.cellLocation;
     let cellChanged = false;
@@ -2946,18 +2879,16 @@ RIL[REQUEST_CHANGE_SIM_PIN2] = function 
                        requestId: options.requestId});
 };
 RIL[REQUEST_ENTER_NETWORK_DEPERSONALIZATION] = null;
 RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
-  this.initRILQuirks();
-
   let calls_length = 0;
   // The RIL won't even send us the length integer if there are no active calls.
   // So only read this integer if the parcel actually has it.
   if (length) {
     calls_length = Buf.readUint32();
   }
   if (!calls_length) {
     this._processCalls(null);
@@ -3464,25 +3395,35 @@ RIL.readDataCall_v6 = function readDataC
   }
   //TODO for now we only support one address and gateway
   if (options.ipaddr) {
     options.ipaddr = options.ipaddr.split(" ")[0];
   }
   if (options.gw) {
     options.gw = options.gw.split(" ")[0];
   }
+  options.ip = null;
+  options.netmask = null;
+  options.broadcast = null;
+  if (options.ipaddr) {
+    options.ip = options.ipaddr.split("/")[0];
+    let ip_value = netHelpers.stringToIP(options.ip);
+    let prefix_len = options.ipaddr.split("/")[1];
+    let mask_value = netHelpers.makeMask(prefix_len);
+    options.netmask = netHelpers.ipToString(mask_value);
+    options.broadcast = netHelpers.ipToString((ip_value & mask_value) + ~mask_value);
+  }
   return options;
 };
 
 RIL[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
-  this.initRILQuirks();
   if (!length) {
     this._processDataCallList(null);
     return;
   }
 
   let version = 0;
   if (!RILQUIRKS_V5_LEGACY) {
     version = Buf.readUint32();
@@ -3731,17 +3672,16 @@ RIL[UNSOLICITED_CDMA_OTA_PROVISION_STATU
 RIL[UNSOLICITED_CDMA_INFO_REC] = null;
 RIL[UNSOLICITED_OEM_HOOK_RAW] = null;
 RIL[UNSOLICITED_RINGBACK_TONE] = null;
 RIL[UNSOLICITED_RESEND_INCALL_MUTE] = null;
 RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) {
   // Prevent response id collision between UNSOLICITED_RIL_CONNECTED and
   // UNSOLICITED_VOICE_RADIO_TECH_CHANGED for Akami on gingerbread branch.
   if (!length) {
-    this.initRILQuirks();
     return;
   }
 
   let version = Buf.readUint32List()[0];
   RILQUIRKS_V5_LEGACY = (version < 5);
   if (DEBUG) {
     debug("Detected RIL version " + version);
     debug("RILQUIRKS_V5_LEGACY is " + RILQUIRKS_V5_LEGACY);
--- a/dom/system/gonk/systemlibs.js
+++ b/dom/system/gonk/systemlibs.js
@@ -205,24 +205,26 @@ let libnetutils = (function () {
 
       if (ret && DEBUG) {
         let error = iface.dhcp_get_errmsg();
         dump("dhcp_do_request failed - " + error.readString());
       }
       let obj = {
         ret: ret | 0,
         ipaddr_str: ipaddrbuf.readString(),
-        mask: netHelpers.makeMask(prefixLen),
+        mask: netHelpers.makeMask(prefixLen.value),
         gateway_str: gatewaybuf.readString(),
         dns1_str: dns1buf.readString(),
         dns2_str: dns2buf.readString(),
         server_str: serverbuf.readString(),
-        lease: lease | 0
+        lease: lease.value | 0
       };
       obj.ipaddr = netHelpers.stringToIP(obj.ipaddr_str);
+      obj.mask_str = netHelpers.ipToString(obj.mask);
+      obj.broadcast_str = netHelpers.ipToString((obj.ipaddr & obj.mask) + ~obj.mask);
       obj.gateway = netHelpers.stringToIP(obj.gateway_str);
       obj.dns1 = netHelpers.stringToIP(obj.dns1_str);
       obj.dns2 = netHelpers.stringToIP(obj.dns2_str);
       obj.server = netHelpers.stringToIP(obj.server_str);
       return obj;
     };
     // dhcp_do_request_renew() went away in newer libnetutils.
     iface.dhcp_do_request_renew = iface.dhcp_do_request;
@@ -283,16 +285,42 @@ let libnetutils = (function () {
 })();
 
 /**
  * Helpers for conversions.
  */
 let netHelpers = {
 
   /**
+   * Swap byte orders for 32-bit value
+   */
+  swap32: function swap32(n) {
+    return (((n >> 24) & 0xFF) <<  0) |
+           (((n >> 16) & 0xFF) <<  8) |
+           (((n >>  8) & 0xFF) << 16) |
+           (((n >>  0) & 0xFF) << 24);
+  },
+
+  /**
+   * Convert network byte order to host byte order
+   * Note: Assume that the system is little endian
+   */
+  ntohl: function ntohl(n) {
+    return this.swap32(n);
+  },
+
+  /**
+   * Convert host byte order to network byte order
+   * Note: Assume that the system is little endian
+   */
+  htonl: function htonl(n) {
+    return this.swap32(n);
+  },
+
+  /**
    * Convert integer representation of an IP address to the string
    * representation.
    *
    * @param ip
    *        IP address in number format.
    */
   ipToString: function ipToString(ip) {
     return ((ip >>  0) & 0xFF) + "." +
@@ -327,13 +355,13 @@ let netHelpers = {
   },
 
   /**
    * Make a subnet mask.
    */
   makeMask: function makeMask(len) {
     let mask = 0;
     for (let i = 0; i < len; ++i) {
-      mask |= (1 << i);
+      mask |= (0x80000000 >> i);
     }
-    return mask;
+    return this.ntohl(mask);
   }
 };
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -260,16 +260,17 @@ var interfaceNamesInGlobalScope =
     "MozSmsMessage",
     "SVGFESpecularLightingElement",
     "StorageObsolete",
     "ContactManager",
     "NSXPathExpression",
     "SVGLineElement",
     "SVGPathSegArcRel",
     "WebGLExtension",
+    "WebGLExtensionDepthTexture",
     "XSLTProcessor",
     "SVGPathSegLinetoVerticalAbs",
     "SVGPathSegLinetoRel",
     "HTMLImageElement",
     "MozSmsEvent",
     "CustomEvent",
     "XMLHttpRequestUpload",
     "SVGFEFuncBElement",
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -941,16 +941,22 @@ var WifiManager = (function() {
 
         // Register as network interface.
         WifiNetworkInterface.name = ifname;
         if (!WifiNetworkInterface.registered) {
           gNetworkManager.registerNetworkInterface(WifiNetworkInterface);
           WifiNetworkInterface.registered = true;
         }
         WifiNetworkInterface.state = Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED;
+        WifiNetworkInterface.ip = null;
+        WifiNetworkInterface.netmask = null;
+        WifiNetworkInterface.broadcast = null;
+        WifiNetworkInterface.gateway = null;
+        WifiNetworkInterface.dns1 = null;
+        WifiNetworkInterface.dns2 = null;
         Services.obs.notifyObservers(WifiNetworkInterface,
                                      kNetworkInterfaceStateChangedTopic,
                                      null);
 
         prepareForStartup(function(already_connected) {
           if (already_connected) {
             callback(0);
             return;
@@ -1262,16 +1268,26 @@ let WifiNetworkInterface = {
   type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
 
   name: null,
 
   // For now we do our own DHCP. In the future this should be handed off
   // to the Network Manager.
   dhcp: false,
 
+  ip: null,
+
+  netmask: null,
+
+  broadcast: null,
+
+  dns1: null,
+
+  dns2: null,
+
   httpProxyHost: null,
 
   httpProxyPort: null,
 
 };
 
 
 // TODO Make the difference between a DOM-based network object and our
@@ -1493,28 +1509,40 @@ function WifiWorker() {
           if (self._reconnectOnDisconnect) {
             self._reconnectOnDisconnect = false;
             WifiManager.reconnect(function(){});
           }
         });
 
         WifiNetworkInterface.state =
           Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED;
+        WifiNetworkInterface.ip = null;
+        WifiNetworkInterface.netmask = null;
+        WifiNetworkInterface.broadcast = null;
+        WifiNetworkInterface.gateway = null;
+        WifiNetworkInterface.dns1 = null;
+        WifiNetworkInterface.dns2 = null;
         Services.obs.notifyObservers(WifiNetworkInterface,
                                      kNetworkInterfaceStateChangedTopic,
                                      null);
 
         break;
     }
   };
 
   WifiManager.ondhcpconnected = function() {
     if (this.info) {
       WifiNetworkInterface.state =
         Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED;
+      WifiNetworkInterface.ip = this.info.ipaddr_str;
+      WifiNetworkInterface.netmask = this.info.mask_str;
+      WifiNetworkInterface.broadcast = this.info.broadcast_str;
+      WifiNetworkInterface.gateway = this.info.gateway_str;
+      WifiNetworkInterface.dns1 = this.info.dns1_str;
+      WifiNetworkInterface.dns2 = this.info.dns2_str;
       Services.obs.notifyObservers(WifiNetworkInterface,
                                    kNetworkInterfaceStateChangedTopic,
                                    null);
 
       self._fireEvent("onconnect", { network: netToDOM(self.currentNetwork) });
     } else {
       WifiManager.disconnect(function(){});
     }
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -14,16 +14,33 @@
 // outparams using the &-operator. But it will have to do as there's no easy
 // solution.
 #include "mozilla/RefPtr.h"
 
 #ifdef MOZ_ENABLE_FREETYPE
 #include <string>
 #endif
 
+/**
+ * Use C++11 nullptr if available; otherwise use a C++ typesafe template; and
+ * for C, fall back to longs.  See bugs 547964 and 626472.
+ * Copy and paste job from nscore.h, see bug 781943
+ */
+#if defined(MOZ_GFX) && !defined(HAVE_NULLPTR)
+#ifndef __cplusplus
+# define nullptr ((void*)0)
+#elif defined(__GNUC__)
+# define nullptr __null
+#elif defined(_WIN64)
+# define nullptr 0LL
+#else
+# define nullptr 0L
+#endif
+#endif /* defined(MOZ_GFX) && !defined(HAVE_NULLPTR) */
+
 struct _cairo_surface;
 typedef _cairo_surface cairo_surface_t;
 
 struct _cairo_scaled_font;
 typedef _cairo_scaled_font cairo_scaled_font_t;
 
 struct ID3D10Device1;
 struct ID3D10Texture2D;
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -1574,62 +1574,93 @@ DrawTargetD2D::FinalizeRTForOperation(Co
   }
 
   mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), NULL, 0xffffffff);
   
   mDevice->Draw(4, 0);
 }
 
 TemporaryRef<ID2D1Geometry>
+DrawTargetD2D::ConvertRectToGeometry(const D2D1_RECT_F& aRect)
+{
+  RefPtr<ID2D1RectangleGeometry> rectGeom;
+  factory()->CreateRectangleGeometry(&aRect, byRef(rectGeom));
+  return rectGeom.forget();
+}
+
+static D2D1_RECT_F
+IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
+{
+  D2D1_RECT_F result;
+  result.left = max(aRect1.left, aRect2.left);
+  result.top = max(aRect1.top, aRect2.top);
+  result.right = min(aRect1.right, aRect2.right);
+  result.bottom = min(aRect1.bottom, aRect2.bottom);
+  return result;
+}
+
+TemporaryRef<ID2D1Geometry>
 DrawTargetD2D::GetClippedGeometry()
 {
   if (mCurrentClippedGeometry) {
     return mCurrentClippedGeometry;
   }
 
-  RefPtr<ID2D1GeometrySink> currentSink;
-
-  factory()->CreatePathGeometry(byRef(mCurrentClippedGeometry));
-  mCurrentClippedGeometry->Open(byRef(currentSink));
-      
+  // if pathGeom is null then pathRect represents the path.
+  RefPtr<ID2D1Geometry> pathGeom;
+  D2D1_RECT_F pathRect;
   std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
-
   if (iter->mPath) {
+    RefPtr<ID2D1PathGeometry> tmpGeometry;
+    factory()->CreatePathGeometry(byRef(tmpGeometry));
+    RefPtr<ID2D1GeometrySink> currentSink;
+    tmpGeometry->Open(byRef(currentSink));
     iter->mPath->GetGeometry()->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
                                          iter->mTransform, currentSink);
+    currentSink->Close();
+    pathGeom = tmpGeometry.forget();
   } else {
-    RefPtr<ID2D1RectangleGeometry> rectGeom;
-    factory()->CreateRectangleGeometry(iter->mBounds, byRef(rectGeom));
-    rectGeom->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
-                       D2D1::IdentityMatrix(), currentSink);
+    pathRect = iter->mBounds;
   }
-  currentSink->Close();
 
   iter++;
   for (;iter != mPushedClips.end(); iter++) {
+    if (!pathGeom) {
+      if (iter->mPath) {
+        pathGeom = ConvertRectToGeometry(pathRect);
+      } else {
+        pathRect = IntersectRect(pathRect, iter->mBounds);
+        continue;
+      }
+    }
+
     RefPtr<ID2D1PathGeometry> newGeom;
     factory()->CreatePathGeometry(byRef(newGeom));
 
+    RefPtr<ID2D1GeometrySink> currentSink;
     newGeom->Open(byRef(currentSink));
 
     if (iter->mPath) {
-      mCurrentClippedGeometry->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
-                                           iter->mTransform, currentSink);
+      pathGeom->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
+                                    iter->mTransform, currentSink);
     } else {
-      RefPtr<ID2D1RectangleGeometry> rectGeom;
-      factory()->CreateRectangleGeometry(iter->mBounds, byRef(rectGeom));
-      mCurrentClippedGeometry->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
-                                                   D2D1::IdentityMatrix(), currentSink);
+      RefPtr<ID2D1Geometry> rectGeom = ConvertRectToGeometry(iter->mBounds);
+      pathGeom->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
+                                    D2D1::IdentityMatrix(), currentSink);
     }
 
     currentSink->Close();
 
-    mCurrentClippedGeometry = newGeom;
+    pathGeom = newGeom.forget();
   }
 
+  if (!pathGeom) {
+    pathGeom = ConvertRectToGeometry(pathRect);
+  }
+  mCurrentClippedGeometry = pathGeom.forget();
   return mCurrentClippedGeometry;
 }
 
 TemporaryRef<ID2D1RenderTarget>
 DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
 {
   HRESULT hr;
 
--- a/gfx/2d/DrawTargetD2D.h
+++ b/gfx/2d/DrawTargetD2D.h
@@ -177,16 +177,17 @@ private:
 
   bool FillGlyphsManual(ScaledFontDWrite *aFont,
                         const GlyphBuffer &aBuffer,
                         const Color &aColor,
                         IDWriteRenderingParams *aParams,
                         const DrawOptions &aOptions = DrawOptions());
 
   TemporaryRef<ID2D1RenderTarget> CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
+  TemporaryRef<ID2D1Geometry> ConvertRectToGeometry(const D2D1_RECT_F& aRect);
   TemporaryRef<ID2D1Geometry> GetClippedGeometry();
 
   TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
 
   TemporaryRef<ID3D10Texture2D> CreateGradientTexture(const GradientStopsD2D *aStops);
   TemporaryRef<ID3D10Texture2D> CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds);
 
   // This creates a (partially) uploaded bitmap for a DataSourceSurface. It
@@ -200,17 +201,17 @@ private:
 
   static const uint32_t test = 4;
 
   IntSize mSize;
 
   RefPtr<ID3D10Device1> mDevice;
   RefPtr<ID3D10Texture2D> mTexture;
   RefPtr<ID3D10Texture2D> mCurrentClipMaskTexture;
-  RefPtr<ID2D1PathGeometry> mCurrentClippedGeometry;
+  RefPtr<ID2D1Geometry> mCurrentClippedGeometry;
   mutable RefPtr<ID2D1RenderTarget> mRT;
 
   // We store this to prevent excessive SetTextRenderingParams calls.
   RefPtr<IDWriteRenderingParams> mTextRenderingParams;
 
   // Temporary texture and render target used for supporting alternative operators.
   RefPtr<ID3D10Texture2D> mTempTexture;
   RefPtr<ID3D10RenderTargetView> mRTView;
--- a/gfx/2d/QuartzSupport.h
+++ b/gfx/2d/QuartzSupport.h
@@ -20,26 +20,26 @@ CGColorSpaceRef THEBES_API CreateSystemC
 // Manages a CARenderer
 struct _CGLPBufferObject;
 struct _CGLContextObject;
 
 enum AllowOfflineRendererEnum { ALLOW_OFFLINE_RENDERER, DISALLOW_OFFLINE_RENDERER };
 
 class nsCARenderer : public mozilla::RefCounted<nsCARenderer> {
 public:
-  nsCARenderer() : mCARenderer(nsnull), mFBOTexture(0), mOpenGLContext(nsnull),
-                   mCGImage(nsnull), mCGData(nsnull), mIOSurface(nsnull), mFBO(0),
+  nsCARenderer() : mCARenderer(nullptr), mFBOTexture(0), mOpenGLContext(nullptr),
+                   mCGImage(nullptr), mCGData(nullptr), mIOSurface(nullptr), mFBO(0),
                    mIOTexture(0),
                    mUnsupportedWidth(UINT32_MAX), mUnsupportedHeight(UINT32_MAX),
                    mAllowOfflineRenderer(DISALLOW_OFFLINE_RENDERER) {}
   ~nsCARenderer();
   nsresult SetupRenderer(void* aCALayer, int aWidth, int aHeight,
                          AllowOfflineRendererEnum aAllowOfflineRenderer);
   nsresult Render(int aWidth, int aHeight, CGImageRef *aOutCAImage);
-  bool isInit() { return mCARenderer != nsnull; }
+  bool isInit() { return mCARenderer != nullptr; }
   /*
    * Render the CALayer to an IOSurface. If no IOSurface
    * is attached then an internal pixel buffer will be
    * used.
    */
   void AttachIOSurface(mozilla::RefPtr<MacIOSurface> aSurface);
   IOSurfaceID GetIOSurfaceID();
   static nsresult DrawSurfaceToCGContext(CGContextRef aContext,
--- a/gfx/2d/QuartzSupport.mm
+++ b/gfx/2d/QuartzSupport.mm
@@ -246,19 +246,19 @@ void MacIOSurfaceLib::LoadLibrary() {
                             RTLD_LAZY | RTLD_LOCAL);
   if (!sIOSurfaceFramework || !sOpenGLFramework || !sCoreGraphicsFramework) {
     if (sIOSurfaceFramework)
       dlclose(sIOSurfaceFramework);
     if (sOpenGLFramework)
       dlclose(sOpenGLFramework);
     if (sCoreGraphicsFramework)
       dlclose(sCoreGraphicsFramework);
-    sIOSurfaceFramework = nsnull;
-    sOpenGLFramework = nsnull;
-    sCoreGraphicsFramework = nsnull;
+    sIOSurfaceFramework = nullptr;
+    sOpenGLFramework = nullptr;
+    sCoreGraphicsFramework = nullptr;
     return;
   }
 
   kPropWidth = GetIOConst("kIOSurfaceWidth");
   kPropHeight = GetIOConst("kIOSurfaceHeight");
   kPropBytesPerElem = GetIOConst("kIOSurfaceBytesPerElement");
   kPropBytesPerRow = GetIOConst("kIOSurfaceBytesPerRow");
   kPropIsGlobal = GetIOConst("kIOSurfaceIsGlobal");
@@ -969,36 +969,36 @@ void nsCARenderer::SaveToDisk(MacIOSurfa
   return;
 
 }
 
 #endif
 
 CGImageRef MacIOSurface::CreateImageFromIOSurfaceContext(CGContextRef aContext) {
   if (!MacIOSurfaceLib::isInit())
-    return nsnull;
+    return nullptr;
 
   return MacIOSurfaceLib::IOSurfaceContextCreateImage(aContext);
 }
 
 TemporaryRef<MacIOSurface> MacIOSurface::IOSurfaceContextGetSurface(CGContextRef aContext) {
   if (!MacIOSurfaceLib::isInit())
-    return nsnull;
+    return nullptr;
 
   IOSurfacePtr surfaceRef = MacIOSurfaceLib::IOSurfaceContextGetSurface(aContext);
   if (!surfaceRef)
-    return nsnull;
+    return nullptr;
 
   // Retain the IOSurface because MacIOSurface will release it
   CFRetain(surfaceRef);
 
   RefPtr<MacIOSurface> ioSurface = new MacIOSurface(surfaceRef);
   if (!ioSurface) {
     ::CFRelease(surfaceRef);
-    return nsnull;
+    return nullptr;
   }
   return ioSurface.forget();
 }
 
 
 CGContextType GetContextType(CGContextRef ref)
 {
   if (!MacIOSurfaceLib::isInit() || !MacIOSurfaceLib::sCGContextGetTypePtr)
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -75,16 +75,17 @@ static const char *sExtensionNames[] = {
     "GL_ANGLE_framebuffer_multisample",
     "GL_OES_rgb8_rgba8",
     "GL_ARB_robustness",
     "GL_EXT_robustness",
     "GL_ARB_sync",
     "GL_OES_EGL_image",
     "GL_OES_EGL_sync",
     "GL_OES_EGL_image_external",
+    "GL_EXT_packed_depth_stencil",
     nullptr
 };
 
 /*
  * XXX - we should really know the ARB/EXT variants of these
  * instead of only handling the symbol if it's exposed directly.
  */
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -1586,16 +1586,17 @@ public:
         ANGLE_framebuffer_multisample,
         OES_rgb8_rgba8,
         ARB_robustness,
         EXT_robustness,
         ARB_sync,
         OES_EGL_image,
         OES_EGL_sync,
         OES_EGL_image_external,
+        EXT_packed_depth_stencil,
         Extensions_Max
     };
 
     bool IsExtensionSupported(GLExtensions aKnownExtension) {
         return mAvailableExtensions[aKnownExtension];
     }
 
     void MarkExtensionUnsupported(GLExtensions aKnownExtension) {
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -176,25 +176,32 @@ public:
   /**
    * Start a new transaction. Nested transactions are not allowed so
    * there must be no transaction currently in progress. 
    * This transaction will render the contents of the layer tree to
    * the given target context. The rendering will be complete when
    * EndTransaction returns.
    */
   virtual void BeginTransactionWithTarget(gfxContext* aTarget) = 0;
+  
+  enum EndTransactionFlags {
+    END_DEFAULT = 0,
+    END_NO_IMMEDIATE_REDRAW = 1 << 0,  // Do not perform the drawing phase
+    END_NO_COMPOSITE = 1 << 1 // Do not composite after drawing thebes layer contents.
+  };
+
   /**
    * Attempts to end an "empty transaction". There must have been no
    * changes to the layer tree since the BeginTransaction().
    * It's possible for this to fail; ThebesLayers may need to be updated
    * due to VRAM data being lost, for example. In such cases this method
    * returns false, and the caller must proceed with a normal layer tree
    * update and EndTransaction.
    */
-  virtual bool EndEmptyTransaction() = 0;
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) = 0;
 
   /**
    * Function called to draw the contents of each ThebesLayer.
    * aRegionToDraw contains the region that needs to be drawn.
    * This would normally be a subregion of the visible region.
    * The callee must draw all of aRegionToDraw. Drawing outside
    * aRegionToDraw will be clipped out or ignored.
    * The callee must draw all of aRegionToDraw.
@@ -218,32 +225,30 @@ public:
    * The origin of aContext is 0,0 in the ThebesLayer.
    */
   typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer,
                                            gfxContext* aContext,
                                            const nsIntRegion& aRegionToDraw,
                                            const nsIntRegion& aRegionToInvalidate,
                                            void* aCallbackData);
 
-  enum EndTransactionFlags {
-    END_DEFAULT = 0,
-    END_NO_IMMEDIATE_REDRAW = 1 << 0  // Do not perform the drawing phase
-  };
-
   /**
    * Finish the construction phase of the transaction, perform the
    * drawing phase, and end the transaction.
    * During the drawing phase, all ThebesLayers in the tree are
    * drawn in tree order, exactly once each, except for those layers
    * where it is known that the visible region is empty.
    */
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT) = 0;
 
+  virtual bool HasShadowManagerInternal() const { return false; }
+  bool HasShadowManager() const { return HasShadowManagerInternal(); }
+
   bool IsSnappingEffectiveTransforms() { return mSnapEffectiveTransforms; } 
 
   /** 
    * Returns true if this LayerManager can properly support layers with
    * SURFACE_COMPONENT_ALPHA. This can include disabling component
    * alpha if required.
    */
   virtual bool AreComponentAlphaLayersEnabled() { return true; }
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -416,16 +416,22 @@ BasicLayerManager::EndTransactionInterna
   mPhase = PHASE_DRAWING;
 #endif
 
   Layer* aLayer = GetRoot();
   RenderTraceLayers(aLayer, "FF00");
 
   mTransactionIncomplete = false;
 
+  if (aFlags & END_NO_COMPOSITE) {
+    // TODO: We should really just set mTarget to null and make sure we can handle that further down the call chain
+    nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
+    mTarget = new gfxContext(surf);
+  }
+
   if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     nsIntRect clipRect;
     if (HasShadowManager()) {
       // If this has a shadow manager, the clip extents of mTarget are meaningless.
       // So instead just use the root layer's visible region bounds.
       const nsIntRect& bounds = mRoot->GetVisibleRegion().GetBounds();
       gfxRect deviceRect =
           mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
@@ -445,19 +451,29 @@ BasicLayerManager::EndTransactionInterna
     if (IsRetained()) {
       nsIntRegion region;
       MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
       if (mUsingDefaultTarget && mDoubleBuffering != BUFFER_NONE) {
         ApplyDoubleBuffering(mRoot, clipRect);
       }
     }
 
-    PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
-    if (mWidget) {
-      FlashWidgetUpdateArea(mTarget);
+    if (aFlags & END_NO_COMPOSITE) {
+      if (IsRetained()) {
+        // Clip the destination out so that we don't draw to it, and
+        // only end up validating ThebesLayers.
+        mTarget->Clip(gfxRect(0, 0, 0, 0));
+        PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
+      }
+      // If we're not retained, then don't composite means do nothing at all.
+    } else {
+      PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
+      if (mWidget) {
+        FlashWidgetUpdateArea(mTarget);
+      }
     }
 
     if (!mTransactionIncomplete) {
       // Clear out target if we have a complete transaction.
       mTarget = nullptr;
     }
   }
 
@@ -503,23 +519,23 @@ BasicLayerManager::FlashWidgetUpdateArea
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     aContext->SetColor(gfxRGBA(r, g, b, 0.2));
     aContext->Paint();
   }
 }
 
 bool
-BasicLayerManager::EndEmptyTransaction()
+BasicLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   if (!mRoot) {
     return false;
   }
 
-  return EndTransactionInternal(nullptr, nullptr);
+  return EndTransactionInternal(nullptr, nullptr, aFlags);
 }
 
 void
 BasicLayerManager::SetRoot(Layer* aLayer)
 {
   NS_ASSERTION(aLayer, "Root can't be null");
   NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
@@ -1034,19 +1050,19 @@ BasicShadowLayerManager::EndTransaction(
   } else if (mShadowTarget) {
     // Draw to shadow target at the recursion tail of the repeat transactions
     ShadowLayerForwarder::ShadowDrawToTarget(mShadowTarget);
     mShadowTarget = nullptr;
   }
 }
 
 bool
-BasicShadowLayerManager::EndEmptyTransaction()
+BasicShadowLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
-  if (!BasicLayerManager::EndEmptyTransaction()) {
+  if (!BasicLayerManager::EndEmptyTransaction(aFlags)) {
     // Return without calling ForwardTransaction. This leaves the
     // ShadowLayerForwarder transaction open; the following
     // EndTransaction will complete it.
     return false;
   }
   ForwardTransaction();
   return true;
 }
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -82,17 +82,17 @@ public:
 
   nsIWidget* GetRetainerWidget() { return mWidget; }
   void ClearRetainerWidget() { mWidget = nullptr; }
 
   virtual bool IsWidgetLayerManager() { return mWidget != nullptr; }
 
   virtual void BeginTransaction();
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
   virtual bool AreComponentAlphaLayersEnabled() { return HasShadowManager(); }
 
   void AbortTransaction();
 
   virtual void SetRoot(Layer* aLayer);
@@ -145,18 +145,16 @@ public:
   already_AddRefed<gfxContext> PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
                                                  const nsIntRegion& aRegion,
                                                  bool* aNeedsClipToVisibleRegion);
   already_AddRefed<gfxContext> PushGroupWithCachedSurface(gfxContext *aTarget,
                                                           gfxASurface::gfxContentType aContent);
   void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
 
   virtual bool IsCompositingCheap() { return false; }
-  virtual bool HasShadowManagerInternal() const { return false; }
-  bool HasShadowManager() const { return HasShadowManagerInternal(); }
   virtual PRInt32 GetMaxTextureSize() const { return PR_INT32_MAX; }
 
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 
@@ -216,17 +214,17 @@ public:
     return this;
   }
 
   virtual PRInt32 GetMaxTextureSize() const;
 
   virtual void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering,
                                 ScreenRotation aRotation) MOZ_OVERRIDE;
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
 
   virtual void SetRoot(Layer* aLayer);
 
   virtual void Mutated(Layer* aLayer);
 
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -22,19 +22,17 @@ BasicThebesLayer::CreateBuffer(Buffer::C
 {
   nsRefPtr<gfxASurface> referenceSurface = mBuffer.GetBuffer();
   if (!referenceSurface) {
     gfxContext* defaultTarget = BasicManager()->GetDefaultTarget();
     if (defaultTarget) {
       referenceSurface = defaultTarget->CurrentSurface();
     } else {
       nsIWidget* widget = BasicManager()->GetRetainerWidget();
-      if (widget) {
-        referenceSurface = widget->GetThebesSurface();
-      } else {
+      if (!widget || !(referenceSurface = widget->GetThebesSurface())) {
         referenceSurface = BasicManager()->GetTarget()->CurrentSurface();
       }
     }
   }
   return referenceSurface->CreateSimilarSurface(
     aType, gfxIntSize(aSize.width, aSize.height));
 }
 
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -23,92 +23,105 @@ ContainerLayerD3D10::ContainerLayerD3D10
 }
 
 ContainerLayerD3D10::~ContainerLayerD3D10()
 {
   while (mFirstChild) {
     RemoveChild(mFirstChild);
   }
 }
+template<class Container>
+static void
+ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter)
+{
+    aChild->SetParent(aContainer);
+    if (!aAfter) {
+        Layer *oldFirstChild = aContainer->GetFirstChild();
+        aContainer->mFirstChild = aChild;
+        aChild->SetNextSibling(oldFirstChild);
+        aChild->SetPrevSibling(nullptr);
+        if (oldFirstChild) {
+            oldFirstChild->SetPrevSibling(aChild);
+        } else {
+            aContainer->mLastChild = aChild;
+        }
+        NS_ADDREF(aChild);
+        aContainer->DidInsertChild(aChild);
+        return;
+    }
+    for (Layer *child = aContainer->GetFirstChild(); 
+        child; child = child->GetNextSibling()) {
+            if (aAfter == child) {
+                Layer *oldNextSibling = child->GetNextSibling();
+                child->SetNextSibling(aChild);
+                aChild->SetNextSibling(oldNextSibling);
+                if (oldNextSibling) {
+                    oldNextSibling->SetPrevSibling(aChild);
+                } else {
+                    aContainer->mLastChild = aChild;
+                }
+                aChild->SetPrevSibling(child);
+                NS_ADDREF(aChild);
+                aContainer->DidInsertChild(aChild);
+                return;
+            }
+    }
+    NS_WARNING("Failed to find aAfter layer!");
+}
+
+template<class Container>
+static void
+ContainerRemoveChild(Container* aContainer, Layer* aChild)
+{
+    if (aContainer->GetFirstChild() == aChild) {
+        aContainer->mFirstChild = aContainer->GetFirstChild()->GetNextSibling();
+        if (aContainer->mFirstChild) {
+            aContainer->mFirstChild->SetPrevSibling(nullptr);
+        } else {
+            aContainer->mLastChild = nullptr;
+        }
+        aChild->SetNextSibling(nullptr);
+        aChild->SetPrevSibling(nullptr);
+        aChild->SetParent(nullptr);
+        aContainer->DidRemoveChild(aChild);
+        NS_RELEASE(aChild);
+        return;
+    }
+    Layer *lastChild = nullptr;
+    for (Layer *child = aContainer->GetFirstChild(); child; 
+        child = child->GetNextSibling()) {
+            if (child == aChild) {
+                // We're sure this is not our first child. So lastChild != NULL.
+                lastChild->SetNextSibling(child->GetNextSibling());
+                if (child->GetNextSibling()) {
+                    child->GetNextSibling()->SetPrevSibling(lastChild);
+                } else {
+                    aContainer->mLastChild = lastChild;
+                }
+                child->SetNextSibling(nullptr);
+                child->SetPrevSibling(nullptr);
+                child->SetParent(nullptr);
+                aContainer->DidRemoveChild(aChild);
+                NS_RELEASE(aChild);
+                return;
+            }
+            lastChild = child;
+    }
+}
 
 void
 ContainerLayerD3D10::InsertAfter(Layer* aChild, Layer* aAfter)
 {
-  aChild->SetParent(this);
-  if (!aAfter) {
-    Layer *oldFirstChild = GetFirstChild();
-    mFirstChild = aChild;
-    aChild->SetNextSibling(oldFirstChild);
-    aChild->SetPrevSibling(nullptr);
-    if (oldFirstChild) {
-      oldFirstChild->SetPrevSibling(aChild);
-    } else {
-      mLastChild = aChild;
-    }
-    NS_ADDREF(aChild);
-    DidInsertChild(aChild);
-    return;
-  }
-  for (Layer *child = GetFirstChild();
-       child; child = child->GetNextSibling()) {
-    if (aAfter == child) {
-      Layer *oldNextSibling = child->GetNextSibling();
-      child->SetNextSibling(aChild);
-      aChild->SetNextSibling(oldNextSibling);
-      if (oldNextSibling) {
-        oldNextSibling->SetPrevSibling(aChild);
-      } else {
-        mLastChild = aChild;
-      }
-      aChild->SetPrevSibling(child);
-      NS_ADDREF(aChild);
-      DidInsertChild(aChild);
-      return;
-    }
-  }
-  NS_WARNING("Failed to find aAfter layer!");
+  ContainerInsertAfter(this, aChild, aAfter);
 }
 
 void
 ContainerLayerD3D10::RemoveChild(Layer *aChild)
 {
-  if (GetFirstChild() == aChild) {
-    mFirstChild = GetFirstChild()->GetNextSibling();
-    if (mFirstChild) {
-      mFirstChild->SetPrevSibling(nullptr);
-    } else {
-      mLastChild = nullptr;
-    }
-    aChild->SetNextSibling(nullptr);
-    aChild->SetPrevSibling(nullptr);
-    aChild->SetParent(nullptr);
-    DidRemoveChild(aChild);
-    NS_RELEASE(aChild);
-    return;
-  }
-  Layer *lastChild = nullptr;
-  for (Layer *child = GetFirstChild(); child;
-       child = child->GetNextSibling()) {
-    if (child == aChild) {
-      // We're sure this is not our first child. So lastChild != NULL.
-      lastChild->SetNextSibling(child->GetNextSibling());
-      if (child->GetNextSibling()) {
-        child->GetNextSibling()->SetPrevSibling(lastChild);
-      } else {
-        mLastChild = lastChild;
-      }
-      child->SetNextSibling(nullptr);
-      child->SetPrevSibling(nullptr);
-      child->SetParent(nullptr);
-      DidRemoveChild(aChild);
-      NS_RELEASE(aChild);
-      return;
-    }
-    lastChild = child;
-  }
+  ContainerRemoveChild(this, aChild);
 }
 
 Layer*
 ContainerLayerD3D10::GetLayer()
 {
   return this;
 }
 
@@ -363,28 +376,33 @@ ContainerLayerD3D10::Validate()
 
 ShadowContainerLayerD3D10::ShadowContainerLayerD3D10(LayerManagerD3D10 *aManager) 
   : ShadowContainerLayer(aManager, NULL)
   , LayerD3D10(aManager)
 {
   mImplData = static_cast<LayerD3D10*>(this);
 }
 
-ShadowContainerLayerD3D10::~ShadowContainerLayerD3D10() {}
+ShadowContainerLayerD3D10::~ShadowContainerLayerD3D10() 
+{
+  while (mFirstChild) {
+    RemoveChild(mFirstChild);
+  }  
+}
 
 void
 ShadowContainerLayerD3D10::InsertAfter(Layer* aChild, Layer* aAfter)
 {
-  mFirstChild = aChild;
+  ContainerInsertAfter(this, aChild, aAfter);
 }
 
 void
 ShadowContainerLayerD3D10::RemoveChild(Layer* aChild)
 {
-
+  ContainerRemoveChild(this, aChild);
 }
 
 void
 ShadowContainerLayerD3D10::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
 {
   DefaultComputeEffectiveTransforms(aTransformToSurface);
 }
 
@@ -404,12 +422,16 @@ ShadowContainerLayerD3D10::RenderLayer()
 void
 ShadowContainerLayerD3D10::Validate()
 {
 }
  
 void
 ShadowContainerLayerD3D10::LayerManagerDestroyed()
 {
+  while (mFirstChild) {
+    GetFirstChildD3D10()->LayerManagerDestroyed();
+    RemoveChild(mFirstChild);
+  }
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d10/ContainerLayerD3D10.h
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.h
@@ -6,19 +6,28 @@
 #ifndef GFX_CONTAINERLAYERD3D10_H
 #define GFX_CONTAINERLAYERD3D10_H
 
 #include "LayerManagerD3D10.h"
 
 namespace mozilla {
 namespace layers {
 
+template<class Container>
+static void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
+template<class Container>
+static void ContainerRemoveChild(Container* aContainer, Layer* aChild);
+
 class ContainerLayerD3D10 : public ContainerLayer,
                             public LayerD3D10
 {
+  template<class Container>
+  friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
+  template<class Container>
+  friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
 public:
   ContainerLayerD3D10(LayerManagerD3D10 *aManager);
   ~ContainerLayerD3D10();
 
   nsIntRect GetVisibleRect() { return mVisibleRegion.GetBounds(); }
 
   /* ContainerLayer implementation */
   virtual void InsertAfter(Layer* aChild, Layer* aAfter);
@@ -42,16 +51,20 @@ public:
 };
 
 // This is a bare-bones implementation of a container layer, only
 // enough to contain a shadow "window texture".  This impl doesn't
 // honor the transform/cliprect/etc. when rendering.
 class ShadowContainerLayerD3D10 : public ShadowContainerLayer,
                                   public LayerD3D10
 {
+  template<class Container>
+  friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
+  template<class Container>
+  friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
 public:
   ShadowContainerLayerD3D10(LayerManagerD3D10 *aManager);
   ~ShadowContainerLayerD3D10();
 
   void InsertAfter(Layer* aChild, Layer* aAfter);
 
   void RemoveChild(Layer* aChild);
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -195,17 +195,17 @@ LayerManagerD3D10::Initialize(bool force
 
     attachments->mVertexBuffer = mVertexBuffer;
   } else {
     mEffect = attachments->mEffect;
     mVertexBuffer = attachments->mVertexBuffer;
     mInputLayout = attachments->mInputLayout;
   }
 
-  if (HasShadowManager()) {
+  if (ShadowLayerForwarder::HasShadowManager()) {
     reporter.SetSuccessful();
     return true;
   }
 
   nsRefPtr<IDXGIDevice> dxgiDevice;
   nsRefPtr<IDXGIAdapter> dxgiAdapter;
 
   mDevice->QueryInterface(dxgiDevice.StartAssignment());
@@ -330,22 +330,22 @@ LayerManagerD3D10::BeginTransaction()
 
 void
 LayerManagerD3D10::BeginTransactionWithTarget(gfxContext* aTarget)
 {
   mTarget = aTarget;
 }
 
 bool
-LayerManagerD3D10::EndEmptyTransaction()
+LayerManagerD3D10::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   if (!mRoot)
     return false;
 
-  EndTransaction(nullptr, nullptr);
+  EndTransaction(nullptr, nullptr, aFlags);
   return true;
 }
 
 void
 LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback,
                                   void* aCallbackData,
                                   EndTransactionFlags aFlags)
 {
@@ -357,17 +357,17 @@ LayerManagerD3D10::EndTransaction(DrawTh
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
 #ifdef MOZ_LAYERS_HAVE_LOG
     MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
     Log();
 #endif
 
-    Render();
+    Render(aFlags);
     mCurrentCallbackInfo.Callback = nullptr;
     mCurrentCallbackInfo.CallbackData = nullptr;
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   Log();
   MOZ_LAYERS_LOG(("]----- EndTransaction"));
 #endif
@@ -698,20 +698,24 @@ LayerManagerD3D10::EnsureReadbackManager
     return;
   }
 
   mReadbackManager = new ReadbackManagerD3D10();
   attachments->mReadbackManager = mReadbackManager;
 }
 
 void
-LayerManagerD3D10::Render()
+LayerManagerD3D10::Render(EndTransactionFlags aFlags)
 {
   static_cast<LayerD3D10*>(mRoot->ImplData())->Validate();
 
+  if (aFlags & END_NO_COMPOSITE) {
+    return;
+  }
+
   SetupPipeline();
 
   float black[] = { 0, 0, 0, 0 };
   device()->ClearRenderTargetView(mRTView, black);
 
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.h
+++ b/gfx/layers/d3d10/LayerManagerD3D10.h
@@ -80,17 +80,17 @@ public:
   { return this; }
 
   virtual void SetRoot(Layer *aLayer);
 
   virtual void BeginTransaction();
 
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
 
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
 
   struct CallbackInfo {
     DrawThebesLayerCallback Callback;
     void *CallbackData;
   };
 
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
@@ -173,17 +173,17 @@ public:
   static void ReportFailure(const nsACString &aMsg, HRESULT aCode);
 
 private:
   void SetupPipeline();
   void UpdateRenderTarget();
   void VerifyBufferSize();
   void EnsureReadbackManager();
 
-  void Render();
+  void Render(EndTransactionFlags aFlags);
 
   nsRefPtr<ID3D10Device1> mDevice;
 
   nsRefPtr<ID3D10Effect> mEffect;
   nsRefPtr<ID3D10InputLayout> mInputLayout;
   nsRefPtr<ID3D10Buffer> mVertexBuffer;
   nsRefPtr<ReadbackManagerD3D10> mReadbackManager;
 
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -182,16 +182,19 @@ CanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 CanvasLayerD3D9::RenderLayer()
 {
   UpdateSurface();
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
   FireDidTransactionCallback();
 
   if (!mTexture)
     return;
 
   /*
    * We flip the Y axis here, note we can only do this because we are in 
    * CULL_NONE mode!
@@ -350,17 +353,17 @@ Layer*
 ShadowCanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 ShadowCanvasLayerD3D9::RenderLayer()
 {
-  if (!mBuffer) {
+  if (!mBuffer || mD3DManager->CompositingDisabled()) {
     return;
   }
 
   mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
 }
 
 
 } /* namespace layers */
--- a/gfx/layers/d3d9/ColorLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp
@@ -14,16 +14,19 @@ ColorLayerD3D9::GetLayer()
   return this;
 }
 
 static void
 RenderColorLayerD3D9(ColorLayer* aLayer, LayerManagerD3D9 *aManager)
 {
   // XXX we might be able to improve performance by using
   // IDirect3DDevice9::Clear
+  if (aManager->CompositingDisabled()) {
+    return;
+  }
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
 
   aManager->device()->SetVertexShaderConstantF(
     CBvLayerQuad,
     ShaderConstantRect(visibleRect.x,
                        visibleRect.y,
                        visibleRect.width,
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -142,31 +142,34 @@ ContainerRender(Container* aContainer,
   ReadbackProcessor readback;
   readback.BuildUpdates(aContainer);
 
   nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
   bool useIntermediate = aContainer->UseIntermediateSurface();
 
   aContainer->mSupportsComponentAlphaChildren = false;
   if (useIntermediate) {
-    aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
-    HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
-                                                   D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
-                                                   D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
-                                                   NULL);
-    if (FAILED(hr)) {
-      aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
-                              hr);
-      return;
+    nsRefPtr<IDirect3DSurface9> renderSurface;
+    if (!aManager->CompositingDisabled()) {
+      aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
+      HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
+                                                     D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+                                                     D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
+                                                     NULL);
+      if (FAILED(hr)) {
+        aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
+                                hr);
+        return;
+      }
+
+      nsRefPtr<IDirect3DSurface9> renderSurface;
+      renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
+      aManager->device()->SetRenderTarget(0, renderSurface);
     }
 
-    nsRefPtr<IDirect3DSurface9> renderSurface;
-    renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
-    aManager->device()->SetRenderTarget(0, renderSurface);
-
     if (aContainer->mVisibleRegion.GetNumRects() == 1 && 
         (aContainer->GetContentFlags() & aContainer->CONTENT_OPAQUE)) {
       // don't need a background, we're going to paint all opaque stuff
       aContainer->mSupportsComponentAlphaChildren = true;
     } else {
       const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform();
       gfxMatrix transform;
       // If we have an opaque ancestor layer, then we can be sure that
@@ -177,22 +180,24 @@ ContainerRender(Container* aContainer,
       if (HasOpaqueAncestorLayer(aContainer) &&
           transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
         // Copy background up from below
         RECT dest = { 0, 0, visibleRect.width, visibleRect.height };
         RECT src = dest;
         ::OffsetRect(&src,
                      visibleRect.x + PRInt32(transform.x0),
                      visibleRect.y + PRInt32(transform.y0));
-        hr = aManager->device()->
-          StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
+        if (!aManager->CompositingDisabled()) {
+          hr = aManager->device()->
+            StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
+        }
       }
       if (hr == S_OK) {
         aContainer->mSupportsComponentAlphaChildren = true;
-      } else {
+      } else if (!aManager->CompositingDisabled()) {
         aManager->device()->
           Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
       }
     }
 
     aManager->device()->
       GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
     renderTargetOffset[0] = (float)visibleRect.x;
@@ -251,17 +256,17 @@ ContainerRender(Container* aContainer,
       static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback);
     } else {
       layerToRender->RenderLayer();
     }
   }
     
   aManager->device()->SetScissorRect(&containerD3D9ClipRect);
 
-  if (useIntermediate) {
+  if (useIntermediate && !aManager->CompositingDisabled()) {
     aManager->device()->SetRenderTarget(0, previousRenderTarget);
     aManager->device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
     aManager->device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);
 
     aManager->device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(visibleRect.x,
                                                           visibleRect.y,
                                                           visibleRect.width,
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -350,17 +350,17 @@ ImageLayerD3D9::GetTexture(Image *aImage
 
   return data->mTexture;
 }
 
 void
 ImageLayerD3D9::RenderLayer()
 {
   ImageContainer *container = GetContainer();
-  if (!container) {
+  if (!container || mD3DManager->CompositingDisabled()) {
     return;
   }
 
   AutoLockImage autoLock(container);
 
   Image *image = autoLock.GetImage();
   if (!image) {
     return;
@@ -604,16 +604,20 @@ Layer*
 ShadowImageLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 ShadowImageLayerD3D9::RenderLayer()
 {
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
+
   if (mBuffer) {
     mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
   } else if (mYCbCrImage) {
     if (!mYCbCrImage->mBufferSize) {
       return;
     }
 
     if (!mYCbCrImage->GetBackendData(mozilla::layers::LAYERS_D3D9)) {
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -116,26 +116,26 @@ LayerManagerD3D9::BeginTransactionWithTa
 }
 
 void
 LayerManagerD3D9::EndConstruction()
 {
 }
 
 bool
-LayerManagerD3D9::EndEmptyTransaction()
+LayerManagerD3D9::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   // If the device reset count from our last EndTransaction doesn't match
   // the current device reset count, the device must have been reset one or
   // more times since our last transaction. In that case, an empty transaction
   // is not possible, because layers may need to be rerendered.
   if (!mRoot || mDeviceResetCount != mDeviceManager->GetDeviceResetCount())
     return false;
 
-  EndTransaction(nullptr, nullptr);
+  EndTransaction(nullptr, nullptr, aFlags);
   return true;
 }
 
 void
 LayerManagerD3D9::EndTransaction(DrawThebesLayerCallback aCallback,
                                  void* aCallbackData,
                                  EndTransactionFlags aFlags)
 {
@@ -144,16 +144,17 @@ LayerManagerD3D9::EndTransaction(DrawThe
   if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     mCurrentCallbackInfo.Callback = aCallback;
     mCurrentCallbackInfo.CallbackData = aCallbackData;
 
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
+    SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
     Render();
     /* Clean this out for sanity */
     mCurrentCallbackInfo.Callback = NULL;
     mCurrentCallbackInfo.CallbackData = NULL;
   }
 
   // Clear mTarget, next transaction could have no target
   mTarget = NULL;
@@ -279,16 +280,22 @@ void
 LayerManagerD3D9::Render()
 {
   if (!mSwapChain->PrepareForRendering()) {
     return;
   }
   deviceManager()->SetupRenderState();
 
   SetupPipeline();
+
+  if (CompositingDisabled()) {
+    static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer();
+    return;
+  }
+
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
   device()->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0);
 
   device()->BeginScene();
 
   const nsIntRect *clipRect = mRoot->GetClipRect();
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -93,17 +93,17 @@ public:
   { return this; }
 
   virtual void BeginTransaction();
 
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
 
   void EndConstruction();
 
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
 
   struct CallbackInfo {
     DrawThebesLayerCallback Callback;
     void *CallbackData;
   };
 
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
@@ -171,16 +171,19 @@ public:
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const { return "D3D9"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   void ReportFailure(const nsACString &aMsg, HRESULT aCode);
 
+  bool CompositingDisabled() { return mCompositingDisabled; }
+  void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
+
 private:
   /* Default device manager instance */
   static DeviceManagerD3D9 *mDefaultDeviceManager;
 
   /* Device manager instance for this layer manager */
   nsRefPtr<DeviceManagerD3D9> mDeviceManager;
 
   /* Swap chain associated with this layer manager */
@@ -204,16 +207,22 @@ private:
 
   /*
    * Device reset count at last paint. Whenever this changes, we need to
    * do a full layer tree update.
    */
   PRUint32 mDeviceResetCount;
 
   /*
+   * True if we should only be drawing layer contents, not
+   * compositing them to the target.
+   */
+  bool mCompositingDisabled;
+
+  /*
    * Render the current layer tree to the active target.
    */
   void Render();
 
   /*
    * Setup the pipeline.
    */
   void SetupPipeline();
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -232,16 +232,20 @@ ThebesLayerD3D9::RenderThebesLayer(Readb
       return;
     }
 
     DrawRegion(drawRegion, mode, readbackUpdates);
 
     mValidRegion = neededRegion;
   }
 
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
+
   SetShaderTransformAndOpacity();
 
   if (mode == SURFACE_COMPONENT_ALPHA) {
     mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1,
                                GetMaskLayer());
     device()->SetTexture(0, mTexture);
     device()->SetTexture(1, mTextureOnWhite);
     device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
@@ -650,17 +654,17 @@ bool
 ShadowThebesLayerD3D9::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerD3D9::RenderThebesLayer()
 {
-  if (!mBuffer) {
+  if (!mBuffer || mD3DManager->CompositingDisabled()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
 }
 
 void
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -44,17 +44,17 @@ static const PRInt32 FLING_REPAINT_INTER
  * Minimum amount of speed along an axis before we begin painting far ahead by
  * adjusting the displayport.
  */
 static const float MIN_SKATE_SPEED = 0.5f;
 
 /**
  * Angle from axis within which we stay axis-locked.
  */
-static const float AXIS_LOCK_ANGLE = M_PI / 6.0;
+static const float AXIS_LOCK_ANGLE = M_PI / 9.0;
 
 /**
  * Duration of a zoom to animation.
  */
 static const TimeDuration ZOOM_TO_DURATION = TimeDuration::FromSeconds(0.25);
 
 /**
  * Computed time function used for sampling frames of a zoom to animation.
@@ -324,16 +324,18 @@ nsEventStatus AsyncPanZoomController::On
     return nsEventStatus_eIgnore;
 
   case PANNING:
     {
       MonitorAutoLock monitor(mMonitor);
       ScheduleComposite();
       RequestContentRepaint();
     }
+    mX.EndTouch();
+    mY.EndTouch();
     SetState(FLING);
     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;
   }
@@ -507,18 +509,16 @@ void AsyncPanZoomController::StartPannin
   SingleTouchData& touch = GetFirstSingleTouch(aEvent);
 
   float dx = mX.PanDistance(),
         dy = mY.PanDistance();
 
   double angle = atan2(dy, dx); // range [-pi, pi]
   angle = fabs(angle); // range [0, pi]
 
-  mX.StartTouch(touch.mScreenPoint.x);
-  mY.StartTouch(touch.mScreenPoint.y);
   SetState(PANNING);
 
   if (angle < AXIS_LOCK_ANGLE || angle > (M_PI - AXIS_LOCK_ANGLE)) {
     mY.LockPanning();
   } else if (fabsf(angle - M_PI / 2) < AXIS_LOCK_ANGLE) {
     mX.LockPanning();
   }
 }
@@ -883,18 +883,18 @@ void AsyncPanZoomController::NotifyLayer
     } else {
       mContentPainterStatus = CONTENT_IDLE;
     }
   }
 
   if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
     mContentPainterStatus = CONTENT_IDLE;
 
-    mX.StopTouch();
-    mY.StopTouch();
+    mX.CancelTouch();
+    mY.CancelTouch();
     mFrameMetrics = aViewportFrame;
     mFrameMetrics.mResolution.width = 1 / mFrameMetrics.mResolution.width;
     mFrameMetrics.mResolution.height = 1 / mFrameMetrics.mResolution.height;
     SetPageRect(mFrameMetrics.mCSSContentRect);
 
     // Bug 776413/fixme: Request a repaint as soon as a page is loaded so that
     // we get a larger displayport. This is very bad because we're wasting a
     // paint and not initializating the displayport correctly.
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -16,57 +16,69 @@ static const float EPSILON = 0.0001f;
  * Maximum acceleration that can happen between two frames. Velocity is
  * throttled if it's above this. This may happen if a time delta is very low,
  * or we get a touch point very far away from the previous position for some
  * reason.
  */
 static const float MAX_EVENT_ACCELERATION = 0.5f;
 
 /**
- * Amount of friction applied during flings when going above
- * VELOCITY_THRESHOLD.
+ * Amount of friction applied during flings.
  */
-static const float FLING_FRICTION_FAST = 0.0025f;
+static const float FLING_FRICTION = 0.013f;
 
 /**
- * Amount of friction applied during flings when going below
- * VELOCITY_THRESHOLD.
+ * Threshold for velocity beneath which we turn off any acceleration we had
+ * during repeated flings.
  */
-static const float FLING_FRICTION_SLOW = 0.0015f;
+static const float VELOCITY_THRESHOLD = 0.1f;
 
 /**
- * Maximum velocity before fling friction increases.
+ * Amount of acceleration we multiply in each time the user flings in one
+ * direction. Every time they let go of the screen, we increase the acceleration
+ * by this amount raised to the power of the amount of times they have let go,
+ * times two (to make the curve steeper).  This stops if the user lets go and we
+ * slow down enough, or if they put their finger down without moving it for a
+ * moment (or in the opposite direction).
  */
-static const float VELOCITY_THRESHOLD = 1.0f;
+static const float ACCELERATION_MULTIPLIER = 1.125f;
 
 /**
  * When flinging, if the velocity goes below this number, we just stop the
  * animation completely. This is to prevent asymptotically approaching 0
  * velocity and rerendering unnecessarily.
  */
 static const float FLING_STOPPED_THRESHOLD = 0.01f;
 
 Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
   : mPos(0.0f),
     mVelocity(0.0f),
+    mAcceleration(0),
     mAsyncPanZoomController(aAsyncPanZoomController),
     mLockPanning(false)
 {
 
 }
 
 void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, const TimeDuration& aTimeDelta) {
   if (mLockPanning) {
     return;
   }
 
   float newVelocity = (mPos - aPos) / aTimeDelta.ToMilliseconds();
 
   bool curVelocityIsLow = fabsf(newVelocity) < 0.01f;
-  bool directionChange = (mVelocity > 0) != (newVelocity != 0);
+  bool curVelocityBelowThreshold = fabsf(newVelocity) < VELOCITY_THRESHOLD;
+  bool directionChange = (mVelocity > 0) != (newVelocity > 0);
+
+  // If we've changed directions, or the current velocity threshold, stop any
+  // acceleration we've accumulated.
+  if (directionChange || curVelocityBelowThreshold) {
+    mAcceleration = 0;
+  }
 
   // If a direction change has happened, or the current velocity due to this new
   // touch is relatively low, then just apply it. If not, throttle it.
   if (curVelocityIsLow || (directionChange && fabs(newVelocity) - EPSILON <= 0.0f)) {
     mVelocity = newVelocity;
   } else {
     float maxChange = fabsf(mVelocity * aTimeDelta.ToMilliseconds() * MAX_EVENT_ACCELERATION);
     mVelocity = NS_MIN(mVelocity + maxChange, NS_MAX(mVelocity - maxChange, newVelocity));
@@ -74,53 +86,60 @@ void Axis::UpdateWithTouchAtDevicePoint(
 
   mVelocity = newVelocity;
   mPos = aPos;
 }
 
 void Axis::StartTouch(PRInt32 aPos) {
   mStartPos = aPos;
   mPos = aPos;
-  mVelocity = 0.0f;
   mLockPanning = false;
 }
 
 PRInt32 Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
-  PRInt32 displacement = NS_lround(mVelocity * aScale * aDelta.ToMilliseconds());
+  float velocityFactor = powf(ACCELERATION_MULTIPLIER,
+                              NS_MAX(0, (mAcceleration - 4) * 3));
+  PRInt32 displacement = NS_lround(mVelocity * aScale * aDelta.ToMilliseconds() * velocityFactor);
   // If this displacement will cause an overscroll, throttle it. Can potentially
   // bring it to 0 even if the velocity is high.
   if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
+    // No need to have a velocity along this axis anymore; it won't take us
+    // anywhere, so we're just spinning needlessly.
+    mVelocity = 0.0f;
     displacement -= DisplacementWillOverscrollAmount(displacement);
   }
   return displacement;
 }
 
 float Axis::PanDistance() {
   return fabsf(mPos - mStartPos);
 }
 
-void Axis::StopTouch() {
+void Axis::EndTouch() {
+  mAcceleration++;
+}
+
+void Axis::CancelTouch() {
   mVelocity = 0.0f;
+  mAcceleration = 0;
 }
 
 void Axis::LockPanning() {
   mLockPanning = true;
 }
 
 bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
   if (fabsf(mVelocity) <= FLING_STOPPED_THRESHOLD) {
     // If the velocity is very low, just set it to 0 and stop the fling,
     // otherwise we'll just asymptotically approach 0 and the user won't
     // actually see any changes.
     mVelocity = 0.0f;
     return false;
-  } else if (fabsf(mVelocity) >= VELOCITY_THRESHOLD) {
-    mVelocity *= NS_MAX(1.0f - FLING_FRICTION_FAST * aDelta.ToMilliseconds(), 0.0);
   } else {
-    mVelocity *= NS_MAX(1.0f - FLING_FRICTION_SLOW * aDelta.ToMilliseconds(), 0.0);
+    mVelocity *= NS_MAX(1.0f - FLING_FRICTION * aDelta.ToMilliseconds(), 0.0);
   }
   return true;
 }
 
 Axis::Overscroll Axis::GetOverscroll() {
   // If the current pan takes the viewport to the left of or above the current
   // page rect.
   bool minus = GetOrigin() < GetPageStart();
--- a/gfx/layers/ipc/Axis.h
+++ b/gfx/layers/ipc/Axis.h
@@ -48,21 +48,28 @@ public:
 
   /**
    * Notify this Axis that a touch has begun, i.e. the user has put their finger
    * on the screen but has not yet tried to pan.
    */
   void StartTouch(PRInt32 aPos);
 
   /**
-   * Notify this Axis that a touch has ended. Useful for stopping flings when a
-   * user puts their finger down in the middle of one (i.e. to stop a previous
-   * touch including its fling so that a new one can take its place).
+   * Notify this Axis that a touch has ended gracefully. This may perform
+   * recalculations of the axis velocity.
    */
-  void StopTouch();
+  void EndTouch();
+
+  /**
+   * Notify this Axis that a touch has ended forcefully. Useful for stopping
+   * flings when a user puts their finger down in the middle of one (i.e. to
+   * stop a previous touch including its fling so that a new one can take its
+   * place).
+   */
+  void CancelTouch();
 
   /**
    * Sets axis locking. This prevents any panning along this axis. If the
    * current touch point is updated and the axis is locked, the velocity will
    * not be recalculated. Any already-existing velocity will however stay the
    * same.
    */
   void LockPanning();
@@ -167,16 +174,22 @@ public:
   virtual PRInt32 GetPointOffset(const nsIntPoint& aPoint) = 0;
   virtual PRInt32 GetRectLength(const gfx::Rect& aRect) = 0;
   virtual PRInt32 GetRectOffset(const gfx::Rect& aRect) = 0;
 
 protected:
   PRInt32 mPos;
   PRInt32 mStartPos;
   float mVelocity;
+  // Acceleration is represented by an int, which is the power we raise a
+  // constant to and then multiply the velocity by whenever it is sampled. We do
+  // this only when we detect that the user wants to do a fast fling; that is,
+  // they are flinging multiple times in a row very quickly, probably trying to
+  // reach one of the extremes of the page.
+  PRInt32 mAcceleration;
   nsRefPtr<AsyncPanZoomController> mAsyncPanZoomController;
   bool mLockPanning;
 };
 
 class AxisX : public Axis {
 public:
   AxisX(AsyncPanZoomController* mAsyncPanZoomController);
   virtual PRInt32 GetPointOffset(const nsIntPoint& aPoint);
--- a/gfx/layers/ipc/GestureEventListener.cpp
+++ b/gfx/layers/ipc/GestureEventListener.cpp
@@ -15,19 +15,28 @@ namespace layers {
 
 /**
  * Maximum time for a touch on the screen and corresponding lift of the finger
  * to be considered a tap. This also applies to double taps, except that it is
  * used twice.
  */
 static const int MAX_TAP_TIME = 300;
 
+/**
+ * Amount of change in span needed to take us from the GESTURE_WAITING_PINCH
+ * state to the GESTURE_PINCH state. This is measured as a change in distance
+ * between the fingers used to compute the span ratio. Note that it is a
+ * distance, not a displacement.
+ */
+static const float PINCH_START_THRESHOLD = 35.0f;
+
 GestureEventListener::GestureEventListener(AsyncPanZoomController* aAsyncPanZoomController)
   : mAsyncPanZoomController(aAsyncPanZoomController),
     mState(GESTURE_NONE),
+    mSpanChange(0.0f),
     mLastTouchInput(MultiTouchInput::MULTITOUCH_START, 0)
 {
 }
 
 GestureEventListener::~GestureEventListener()
 {
 }
 
@@ -140,16 +149,20 @@ nsEventStatus GestureEventListener::Hand
           MAX_TAP_TIME);
       }
     }
 
     if (mState == GESTURE_WAITING_SINGLE_TAP) {
       mState = GESTURE_NONE;
     }
 
+    if (!mTouches.Length()) {
+      mSpanChange = 0.0f;
+    }
+
     break;
   }
   case MultiTouchInput::MULTITOUCH_CANCEL:
     // This gets called if there's a touch that has to bail for weird reasons
     // like pinching and then moving away from the window that the pinch was
     // started in without letting go of the screen.
     HandlePinchGestureEvent(event, true);
     break;
@@ -167,34 +180,53 @@ nsEventStatus GestureEventListener::Hand
                       secondTouch = mTouches[mTouches.Length() - 1].mScreenPoint;
     nsIntPoint focusPoint =
       nsIntPoint((firstTouch.x + secondTouch.x)/2,
                  (firstTouch.y + secondTouch.y)/2);
     float currentSpan =
       float(NS_hypot(firstTouch.x - secondTouch.x,
                      firstTouch.y - secondTouch.y));
 
-    if (mState == GESTURE_NONE) {
-      PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START,
-                                   aEvent.mTime,
-                                   focusPoint,
-                                   currentSpan,
-                                   currentSpan);
+    switch (mState) {
+    case GESTURE_NONE:
+      mPreviousSpan = currentSpan;
+      mState = GESTURE_WAITING_PINCH;
+      // Deliberately fall through. If the user pinched and took their fingers
+      // off the screen such that they still had 1 left on it, we want there to
+      // be no resistance. We should only reset |mSpanChange| once all fingers
+      // are off the screen.
+    case GESTURE_WAITING_PINCH: {
+      mSpanChange += fabsf(currentSpan - mPreviousSpan);
+      if (mSpanChange > PINCH_START_THRESHOLD) {
+        PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_START,
+                                     aEvent.mTime,
+                                     focusPoint,
+                                     currentSpan,
+                                     currentSpan);
 
-      mAsyncPanZoomController->HandleInputEvent(pinchEvent);
+        mAsyncPanZoomController->HandleInputEvent(pinchEvent);
 
-      mState = GESTURE_PINCH;
-    } else {
+        mState = GESTURE_PINCH;
+      }
+
+      break;
+    }
+    case GESTURE_PINCH: {
       PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_SCALE,
                                    aEvent.mTime,
                                    focusPoint,
                                    currentSpan,
                                    mPreviousSpan);
 
       mAsyncPanZoomController->HandleInputEvent(pinchEvent);
+      break;
+    }
+    default:
+      // What?
+      break;
     }
 
     mPreviousSpan = currentSpan;
 
     rv = nsEventStatus_eConsumeNoDefault;
   } else if (mState == GESTURE_PINCH) {
     PinchGestureInput pinchEvent(PinchGestureInput::PINCHGESTURE_END,
                                  aEvent.mTime,
--- a/gfx/layers/ipc/GestureEventListener.h
+++ b/gfx/layers/ipc/GestureEventListener.h
@@ -56,17 +56,22 @@ public:
    * callbacks.
    */
   AsyncPanZoomController* GetAsyncPanZoomController();
 
 protected:
   enum GestureState {
     // There's no gesture going on, and we don't think we're about to enter one.
     GESTURE_NONE,
-    // There's a pinch happening, which occurs when there are two touch inputs.
+    // We have detected that two or more fingers are on the screen, but there
+    // hasn't been enough movement yet to make us start actually zooming the
+    // screen.
+    GESTURE_WAITING_PINCH,
+    // There are two or more fingers on the screen, and the user has already
+    // pinched enough for us to start zooming the screen.
     GESTURE_PINCH,
     // A touch start has happened and it may turn into a tap. We use this
     // because, if we put down two fingers and then lift them very quickly, this
     // may be mistaken for a tap.
     GESTURE_WAITING_SINGLE_TAP,
     // A single tap has happened for sure, and we're waiting for a second tap.
     GESTURE_WAITING_DOUBLE_TAP
   };
@@ -133,16 +138,24 @@ protected:
   nsTArray<SingleTouchData> mTouches;
 
   /**
    * Current gesture we're dealing with.
    */
   GestureState mState;
 
   /**
+   * Total change in span since we detected a pinch gesture. Only used when we
+   * are in the |GESTURE_WAITING_PINCH| state and need to know how far zoomed
+   * out we are compared to our original pinch span. Note that this does _not_
+   * continue to be updated once we jump into the |GESTURE_PINCH| state.
+   */
+  float mSpanChange;
+
+  /**
    * Previous span calculated for the purposes of setting inside a
    * PinchGestureInput.
    */
   float mPreviousSpan;
 
   /**
    * Stores the time a touch started, used for detecting a tap gesture. Only
    * valid when there's exactly one touch in mTouches. This is the time that the
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -224,16 +224,19 @@ CanvasLayerOGL::UpdateSurface()
   }
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
                             const nsIntPoint& aOffset)
 {
   UpdateSurface();
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   FireDidTransactionCallback();
 
   mOGLManager->MakeCurrent();
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
@@ -441,16 +444,19 @@ ShadowCanvasLayerOGL::GetLayer()
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
   if (!mTexImage && !IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
     return;
   }
 
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   mOGLManager->MakeCurrent();
 
   gfx3DMatrix effectiveTransform = GetEffectiveTransform();
   gfxPattern::GraphicsFilter filter = mFilter;
 #ifdef ANDROID
   // Bug 691354
   // Using the LINEAR filter we get unexplained artifacts.
   // Use NEAREST when no scaling is required.
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -7,16 +7,20 @@
 
 namespace mozilla {
 namespace layers {
 
 static void
 RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
                  const nsIntPoint& aOffset)
 {
+  if (aManager->CompositingDisabled()) {
+    return;
+  }
+
   aManager->MakeCurrent();
 
   // XXX we might be able to improve performance by using glClear
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
 
   /* Multiply color by the layer opacity, as the shader
    * ignores layer opacity and expects a final color to
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -174,22 +174,24 @@ ContainerRender(Container* aContainer,
         mode = LayerManagerOGL::InitModeCopy;
         framebufferRect.x += transform.x0;
         framebufferRect.y += transform.y0;
         aContainer->mSupportsComponentAlphaChildren = true;
       }
     }
 
     aContainer->gl()->PushViewportRect();
-    framebufferRect -= childOffset; 
-    aManager->CreateFBOWithTexture(framebufferRect,
-                                   mode,
-                                   aPreviousFrameBuffer,
-                                   &frameBuffer,
-                                   &containerSurface);
+    framebufferRect -= childOffset;
+    if (!aManager->CompositingDisabled()) {
+      aManager->CreateFBOWithTexture(framebufferRect,
+                                     mode,
+                                     aPreviousFrameBuffer,
+                                     &frameBuffer,
+                                     &containerSurface);
+    }
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
   } else {
     frameBuffer = aPreviousFrameBuffer;
     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
   }
 
@@ -234,55 +236,57 @@ ContainerRender(Container* aContainer,
 #endif
     
     // Restore the viewport
     aContainer->gl()->PopViewportRect();
     nsIntRect viewport = aContainer->gl()->ViewportRect();
     aManager->SetupPipeline(viewport.width, viewport.height,
                             LayerManagerOGL::ApplyWorldTransform);
     aContainer->gl()->PopScissorRect();
-
     aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
-    aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
-    aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+    if (!aManager->CompositingDisabled()) {
+      aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
-    aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
+      aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+
+      aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
 
-    MaskType maskType = MaskNone;
-    if (aContainer->GetMaskLayer()) {
-      if (!aContainer->GetTransform().CanDraw2D()) {
-        maskType = Mask3d;
-      } else {
-        maskType = Mask2d;
+      MaskType maskType = MaskNone;
+      if (aContainer->GetMaskLayer()) {
+        if (!aContainer->GetTransform().CanDraw2D()) {
+          maskType = Mask3d;
+        } else {
+          maskType = Mask2d;
+        }
       }
-    }
-    ShaderProgramOGL *rgb =
-      aManager->GetFBOLayerProgram(maskType);
+      ShaderProgramOGL *rgb =
+        aManager->GetFBOLayerProgram(maskType);
 
-    rgb->Activate();
-    rgb->SetLayerQuadRect(visibleRect);
-    rgb->SetLayerTransform(transform);
-    rgb->SetLayerOpacity(opacity);
-    rgb->SetRenderOffset(aOffset);
-    rgb->SetTextureUnit(0);
-    rgb->LoadMask(aContainer->GetMaskLayer());
+      rgb->Activate();
+      rgb->SetLayerQuadRect(visibleRect);
+      rgb->SetLayerTransform(transform);
+      rgb->SetLayerOpacity(opacity);
+      rgb->SetRenderOffset(aOffset);
+      rgb->SetTextureUnit(0);
+      rgb->LoadMask(aContainer->GetMaskLayer());
 
-    if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
-      // 2DRect case, get the multiplier right for a sampler2DRect
-      rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
-    }
+      if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
+        // 2DRect case, get the multiplier right for a sampler2DRect
+        rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
+      }
 
-    // Drawing is always flipped, but when copying between surfaces we want to avoid
-    // this. Pass true for the flip parameter to introduce a second flip
-    // that cancels the other one out.
-    aManager->BindAndDrawQuad(rgb, true);
+      // Drawing is always flipped, but when copying between surfaces we want to avoid
+      // this. Pass true for the flip parameter to introduce a second flip
+      // that cancels the other one out.
+      aManager->BindAndDrawQuad(rgb, true);
 
-    // Clean up resources.  This also unbinds the texture.
-    aContainer->gl()->fDeleteTextures(1, &containerSurface);
+      // Clean up resources.  This also unbinds the texture.
+      aContainer->gl()->fDeleteTextures(1, &containerSurface);
+    }
   } else {
     aContainer->gl()->PopScissorRect();
   }
 }
 
 ContainerLayerOGL::ContainerLayerOGL(LayerManagerOGL *aManager)
   : ContainerLayer(aManager, NULL)
   , LayerOGL(aManager)
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -220,17 +220,17 @@ ImageLayerOGL::GetLayer()
 }
 
 void
 ImageLayerOGL::RenderLayer(int,
                            const nsIntPoint& aOffset)
 {
   nsRefPtr<ImageContainer> container = GetContainer();
 
-  if (!container)
+  if (!container || mOGLManager->CompositingDisabled())
     return;
 
   mOGLManager->MakeCurrent();
 
   AutoLockImage autoLock(container);
 
   Image *image = autoLock.GetImage();
   if (!image) {
@@ -870,16 +870,19 @@ void ShadowImageLayerOGL::UploadSharedYU
   UploadYUVToTexture(gl(), data, &mYUVTexture[0], &mYUVTexture[1], &mYUVTexture[2]);
 }
 
 
 void
 ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                  const nsIntPoint& aOffset)
 {
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   mOGLManager->MakeCurrent();
   if (mImageContainerID) {
     ImageContainerParent::SetCompositorIDForImage(mImageContainerID,
                                                   mOGLManager->GetCompositorID());
     PRUint32 imgVersion = ImageContainerParent::GetSharedImageVersion(mImageContainerID);
     if (imgVersion != mImageVersion) {
       SharedImage* img = ImageContainerParent::GetSharedImage(mImageContainerID);
       if (img && (img->type() == SharedImage::TYUVImage)) {
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -375,22 +375,22 @@ LayerManagerOGL::BeginTransactionWithTar
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
   mTarget = aTarget;
 }
 
 bool
-LayerManagerOGL::EndEmptyTransaction()
+LayerManagerOGL::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   if (!mRoot)
     return false;
 
-  EndTransaction(nullptr, nullptr);
+  EndTransaction(nullptr, nullptr, aFlags);
   return true;
 }
 
 void
 LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
                                 void* aCallbackData,
                                 EndTransactionFlags aFlags)
 {
@@ -406,16 +406,17 @@ LayerManagerOGL::EndTransaction(DrawTheb
 
   if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
     mThebesLayerCallback = aCallback;
     mThebesLayerCallbackData = aCallbackData;
+    SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
 
     Render();
 
     mThebesLayerCallback = nullptr;
     mThebesLayerCallbackData = nullptr;
   }
 
   mTarget = NULL;
@@ -769,16 +770,23 @@ LayerManagerOGL::Render()
   if (clipRect) {
     nsIntRect r = *clipRect;
     WorldTransformRect(r);
     mGLContext->fScissor(r.x, r.y, r.width, r.height);
   } else {
     mGLContext->fScissor(0, 0, width, height);
   }
 
+  if (CompositingDisabled()) {
+    RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
+                             nsIntPoint(0, 0));
+    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+    return;
+  }
+
   mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
 
   // If the Java compositor is being used, this clear will be done in
   // DrawWindowUnderlay. Make sure the bits used here match up with those used
   // in mobile/android/base/gfx/LayerRenderer.java
 #ifndef MOZ_JAVA_COMPOSITOR
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -97,17 +97,17 @@ public:
   }
 
   void BeginTransaction();
 
   void BeginTransactionWithTarget(gfxContext* aTarget);
 
   void EndConstruction();
 
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
 
   virtual void SetRoot(Layer* aLayer) { mRoot = aLayer; }
 
   virtual bool CanUseCanvasLayerForSize(const gfxIntSize &aSize)
   {
@@ -345,16 +345,19 @@ public:
   gfxMatrix& GetWorldTransform(void);
   void WorldTransformRect(nsIntRect& aRect);
 
   /**
    * Set the size of the surface we're rendering to.
    */
   void SetSurfaceSize(int width, int height);
 
+  bool CompositingDisabled() { return mCompositingDisabled; }
+  void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
+
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
@@ -386,16 +389,17 @@ private:
    *  flipped and unflipped textures */
   GLuint mQuadVBO;
 
   /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
 
   /** Misc */
   bool mHasBGRA;
+  bool mCompositingDisabled;
 
   /**
    * When rendering to an EGL surface (e.g. on Android), we rely on being told
    * about size changes (via SetSurfaceSize) rather than pulling this information
    * from the widget, since the widget's information can lag behind.
    */
   bool mIsRenderingToEGLSurface;
 
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -83,16 +83,18 @@ public:
 
   enum { PAINT_WILL_RESAMPLE = ThebesLayerBuffer::PAINT_WILL_RESAMPLE };
   virtual PaintState BeginPaint(ContentType aContentType,
                                 PRUint32 aFlags) = 0;
 
   void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
                 PRUint32 aFlags);
 
+  void EndUpdate();
+
   nsIntSize GetSize() {
     if (mTexImage)
       return mTexImage->GetSize();
     return nsIntSize(0, 0);
   }
 
   bool Initialised() { return mInitialised; }
 
@@ -103,33 +105,38 @@ protected:
 
   ThebesLayer* mLayer;
   LayerOGL* mOGLLayer;
   nsRefPtr<TextureImage> mTexImage;
   nsRefPtr<TextureImage> mTexImageOnWhite;
   bool mInitialised;
 };
 
+void ThebesLayerBufferOGL::EndUpdate()
+{
+  if (mTexImage && mTexImage->InUpdate()) {
+    mTexImage->EndUpdate();
+  }
+
+  if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
+    mTexImageOnWhite->EndUpdate();
+  }
+}
+
 void
 ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
                                LayerManagerOGL* aManager,
                                PRUint32 aFlags)
 {
   NS_ASSERTION(Initialised(), "RenderTo with uninitialised buffer!");
 
   if (!mTexImage || !Initialised())
     return;
 
-  if (mTexImage->InUpdate()) {
-    mTexImage->EndUpdate();
-  }
-
-  if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
-    mTexImageOnWhite->EndUpdate();
-  }
+  EndUpdate();
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     nsRefPtr<gfxImageSurface> surf = 
       gl()->GetTexImage(mTexImage->GetTextureID(), false, mTexImage->GetShaderProgramType());
     
     WriteSnapshotToDumpFile(mLayer, surf);
   }
@@ -833,16 +840,21 @@ ThebesLayerOGL::RenderLayer(int aPreviou
       // here (OR doesn't automatically simplify to the simplest possible
       // representation of a region.)
       nsIntRegion tmp;
       tmp.Or(mVisibleRegion, state.mRegionToDraw);
       mValidRegion.Or(mValidRegion, tmp);
     }
   }
 
+  if (mOGLManager->CompositingDisabled()) {
+    mBuffer->EndUpdate();
+    return;
+  }
+
   // Drawing thebes layers can change the current context, reset it.
   gl()->MakeCurrent();
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
   mBuffer->RenderTo(aOffset, mOGLManager, flags);
 }
 
 Layer*
@@ -1094,17 +1106,17 @@ ShadowThebesLayerOGL::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
-  if (!mBuffer) {
+  if (!mBuffer || mOGLManager->CompositingDisabled()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
--- a/gfx/layers/opengl/TiledThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/TiledThebesLayerOGL.cpp
@@ -110,20 +110,19 @@ TiledLayerBufferOGL::ValidateTile(TiledT
 #endif
   return aTile;
 }
 
 TiledThebesLayerOGL::TiledThebesLayerOGL(LayerManagerOGL *aManager)
   : ShadowThebesLayer(aManager, nullptr)
   , LayerOGL(aManager)
   , mVideoMemoryTiledBuffer(aManager->gl())
+  , mReusableTileStore(nullptr)
 {
   mImplData = static_cast<LayerOGL*>(this);
-  // XXX Add a pref for reusable tile store size
-  mReusableTileStore = new ReusableTileStoreOGL(aManager->gl(), 1);
 }
 
 TiledThebesLayerOGL::~TiledThebesLayerOGL()
 {
   mMainMemoryTiledBuffer.ReadUnlock();
   if (mReusableTileStore)
     delete mReusableTileStore;
 }
@@ -140,16 +139,27 @@ TiledThebesLayerOGL::PaintedTiledLayerBu
 }
 
 void
 TiledThebesLayerOGL::ProcessUploadQueue()
 {
   if (mRegionToUpload.IsEmpty())
     return;
 
+  // We should only be retaining old tiles if we're not fixed position.
+  // Fixed position layers don't/shouldn't move on the screen, so retaining
+  // tiles is not useful and often results in rendering artifacts.
+  if (mReusableTileStore && mIsFixedPosition) {
+    delete mReusableTileStore;
+    mReusableTileStore = nullptr;
+  } else if (!mReusableTileStore && !mIsFixedPosition) {
+    // XXX Add a pref for reusable tile store size
+    mReusableTileStore = new ReusableTileStoreOGL(gl(), 1);
+  }
+
   gfxSize resolution(1, 1);
   if (mReusableTileStore) {
     // Work out render resolution by multiplying the resolution of our ancestors.
     // Only container layers can have frame metrics, so we start off with a
     // resolution of 1, 1.
     // XXX For large layer trees, it would be faster to do this once from the
     //     root node upwards and store the value on each layer.
     for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -81,35 +81,39 @@ class EvalScriptGuard
 {
     JSContext *cx_;
     Rooted<JSScript*> script_;
 
     /* These fields are only valid if lookup_.str is non-NULL. */
     EvalCacheLookup lookup_;
     EvalCache::AddPtr p_;
 
+    Rooted<JSLinearString*> lookupStr_;
+
   public:
     EvalScriptGuard(JSContext *cx)
-      : cx_(cx), script_(cx)
+      : cx_(cx), script_(cx), lookupStr_(cx)
     {
         lookup_.str = NULL;
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
+            lookup_.str = lookupStr_;
             if (lookup_.str && IsEvalCacheCandidate(script_))
                 cx_->runtime->evalCache.relookupOrAdd(p_, lookup_, script_);
         }
     }
 
     void lookupInEvalCache(JSLinearString *str, JSFunction *caller, unsigned staticLevel)
     {
+        lookupStr_ = str;
         lookup_.str = str;
         lookup_.caller = caller;
         lookup_.staticLevel = staticLevel;
         lookup_.version = cx_->findVersion();
         lookup_.compartment = cx_->compartment;
         p_ = cx_->runtime->evalCache.lookupForAdd(lookup_);
         if (p_) {
             script_ = *p_;
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -818,16 +818,18 @@ MapIteratorObject::next_impl(JSContext *
         return js_ThrowStopIteration(cx);
     if (range->empty()) {
         cx->delete_(range);
         thisobj.setReservedSlot(RangeSlot, PrivateValue(NULL));
         return js_ThrowStopIteration(cx);
     }
 
     Value pair[2] = { range->front().key.get(), range->front().value };
+    AutoValueArray root(cx, pair, 2);
+
     JSObject *pairobj = NewDenseCopiedArray(cx, 2, pair);
     if (!pairobj)
         return false;
     range->popFront();
     args.rval().setObject(*pairobj);
     return true;
 }
 
@@ -965,17 +967,17 @@ MapObject::construct(JSContext *cx, unsi
         return false;
     }
     obj->setPrivate(map);
 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.hasDefined(0)) {
         ForOfIterator iter(cx, args[0]);
         while (iter.next()) {
-            JSObject *pairobj = js_ValueToNonNullObject(cx, iter.value());
+            RootedObject pairobj(cx, js_ValueToNonNullObject(cx, iter.value()));
             if (!pairobj)
                 return false;
 
             RootedValue key(cx);
             if (!pairobj->getElement(cx, 0, &key))
                 return false;
             HashableValue hkey;
             if (!hkey.setValue(cx, key))
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -82,30 +82,22 @@ BUILD_TOOLS	= $(WIN_TOP_SRC)/build/unix
 else
 win_srcdir	:= $(srcdir)
 BUILD_TOOLS	= $(topsrcdir)/build/unix
 endif
 
 CONFIG_TOOLS	= $(MOZ_BUILD_ROOT)/config
 AUTOCONF_TOOLS	= $(topsrcdir)/build/autoconf
 
-ifeq ($(OS_ARCH),QNX)
-ifeq ($(OS_TARGET),NTO)
-LD		:= qcc -Vgcc_ntox86 -nostdlib
-else
-LD		:= $(CC)
-endif
-endif
-
 #
 # Strip off the excessively long version numbers on these platforms,
 # but save the version to allow multiple versions of the same base
 # platform to be built in the same tree.
 #
-ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD OSF1 SunOS,$(OS_ARCH)))
+ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD SunOS,$(OS_ARCH)))
 OS_RELEASE	:= $(basename $(OS_RELEASE))
 
 # Allow the user to ignore the OS_VERSION, which is usually irrelevant.
 ifdef WANT_MOZILLA_CONFIG_OS_VERSION
 OS_VERS		:= $(suffix $(OS_RELEASE))
 OS_VERSION	:= $(shell echo $(OS_VERS) | sed 's/-.*//')
 endif
 
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -496,27 +496,16 @@ ifdef IS_COMPONENT
 ifneq ($(HAS_EXTRAEXPORTS),1)
 MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 endif # HAS_EXTRAEXPORTS
 endif # IS_COMPONENT
 endif # AIX
 
 #
-# OSF1: add -B symbolic flag for components
-#
-ifeq ($(OS_ARCH),OSF1)
-ifdef IS_COMPONENT
-ifeq ($(GNU_CC)$(GNU_CXX),)
-EXTRA_DSO_LDOPTS += -B symbolic
-endif
-endif
-endif
-
-#
 # Linux: add -Bsymbolic flag for components
 #
 ifeq ($(OS_ARCH),Linux)
 ifdef IS_COMPONENT
 EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic
 endif
 endif
 
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -185,16 +185,19 @@ frontend::CompileScript(JSContext *cx, H
 
 #if JS_HAS_XML_SUPPORT
         if (!pn->isKind(PNK_SEMI) || !pn->pn_kid || !pn->pn_kid->isXMLItem())
             onlyXML = false;
 #endif
         parser.freeTree(pn);
     }
 
+    if (tokenStream.hasSourceMap())
+        ss->setSourceMap(tokenStream.releaseSourceMap());
+
 #if JS_HAS_XML_SUPPORT
     /*
      * Prevent XML data theft via <script src="http://victim.com/foo.xml">.
      * For background, see:
      *
      * https://bugzilla.mozilla.org/show_bug.cgi?id=336551
      */
     if (pn && onlyXML && !callerFrame) {
@@ -298,18 +301,20 @@ frontend::CompileFunctionBody(JSContext 
         /*
          * NB: do not use AutoLocalNameArray because it will release space
          * allocated from cx->tempLifoAlloc by DefineArg.
          */
         BindingVector names(cx);
         if (!GetOrderedBindings(cx, funsc.bindings, &names))
             return false;
 
+        RootedPropertyName name(cx);
         for (unsigned i = 0; i < nargs; i++) {
-            if (!DefineArg(fn, names[i].maybeName, i, &parser))
+            name = names[i].maybeName;
+            if (!DefineArg(fn, name, i, &parser))
                 return false;
         }
     }
 
     /*
      * After we're done parsing, we must fold constants, analyze any nested
      * functions, and generate code for this function, including a stop opcode
      * at the end.
@@ -331,13 +336,16 @@ frontend::CompileFunctionBody(JSContext 
 
     if (fn->pn_body) {
         JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
         fn->pn_body->append(pn);
         fn->pn_body->pn_pos = pn->pn_pos;
         pn = fn->pn_body;
     }
 
+    if (parser.tokenStream.hasSourceMap())
+        ss->setSourceMap(parser.tokenStream.releaseSourceMap());
+
     if (!EmitFunctionScript(cx, &funbce, pn))
         return false;
 
     return true;
 }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -464,17 +464,17 @@ CheckStrictAssignment(JSContext *cx, Par
 
 /*
  * Check that it is permitted to introduce a binding for atom.  Strict mode
  * forbids introducing new definitions for 'eval', 'arguments', or for any
  * strict mode reserved keyword.  Use pn for reporting error locations, or use
  * tc's token stream if pn is NULL.
  */
 bool
-CheckStrictBinding(JSContext *cx, Parser *parser, PropertyName *name, ParseNode *pn)
+CheckStrictBinding(JSContext *cx, Parser *parser, HandlePropertyName name, ParseNode *pn)
 {
     if (!parser->tc->sc->needStrictChecks())
         return true;
 
     JSAtomState *atomState = &cx->runtime->atomState;
     if (name == atomState->evalAtom ||
         name == atomState->argumentsAtom ||
         FindKeyword(name->charsZ(), name->length()))
@@ -484,17 +484,17 @@ CheckStrictBinding(JSContext *cx, Parser
             return false;
         return parser->reportStrictModeError(pn, JSMSG_BAD_BINDING, bytes.ptr());
     }
 
     return true;
 }
 
 static bool
-ReportBadParameter(JSContext *cx, Parser *parser, JSAtom *name, unsigned errorNumber)
+ReportBadParameter(JSContext *cx, Parser *parser, HandlePropertyName name, unsigned errorNumber)
 {
     Definition *dn = parser->tc->decls.lookupFirst(name);
     JSAutoByteString bytes;
     return js_AtomToPrintableString(cx, name, &bytes) &&
            parser->reportStrictModeError(dn, errorNumber, bytes.ptr());
 }
 
 static bool
@@ -873,23 +873,23 @@ MakeDefIntoUse(Definition *dn, ParseNode
 /*
  * Parameter block types for the several Binder functions.  We use a common
  * helper function signature in order to share code among destructuring and
  * simple variable declaration parsers.  In the destructuring case, the binder
  * function is called indirectly from the variable declaration parser by way
  * of CheckDestructuring and its friends.
  */
 typedef bool
-(*Binder)(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+(*Binder)(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 static bool
-BindLet(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 static bool
-BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 struct frontend::BindData {
     BindData(JSContext *cx) : let(cx) {}
 
     ParseNode       *pn;        /* name node for definition processing and
                                    error source coordinates */
     JSOp            op;         /* prolog bytecode or nop */
     Binder          binder;     /* binder, discriminates u */
@@ -1134,17 +1134,17 @@ LeaveFunction(ParseNode *fn, Parser *par
     return true;
 }
 
 /*
  * DefineArg is called for both the formals of a regular function definition
  * and the formals specified by the Function constructor.
  */
 bool
-frontend::DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser)
+frontend::DefineArg(ParseNode *pn, HandlePropertyName name, unsigned i, Parser *parser)
 {
     JSContext *cx = parser->context;
     TreeContext *tc = parser->tc;
     SharedContext *sc = tc->sc;
 
     /*
      * Make an argument definition node, distinguished by being in
      * parser->tc->decls but having PNK_NAME kind and JSOP_NOP op. Insert it in
@@ -1174,33 +1174,33 @@ frontend::DefineArg(ParseNode *pn, Prope
     if (!argpn->pn_cookie.set(cx, tc->staticLevel, i))
         return false;
     argpn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 #if JS_HAS_DESTRUCTURING
 static bool
-BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
+BindDestructuringArg(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
     TreeContext *tc = parser->tc;
     JS_ASSERT(tc->sc->inFunction());
 
     /*
      * NB: Check tc->decls rather than tc->sc->bindings, because destructuring
      *     bindings aren't added to tc->sc->bindings until after all arguments have
      *     been parsed.
      */
-    if (tc->decls.lookupFirst(atom)) {
+    if (tc->decls.lookupFirst(name)) {
         parser->reportError(NULL, JSMSG_DESTRUCT_DUP_ARG);
         return false;
     }
 
     ParseNode *pn = data->pn;
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
     /*
      * Distinguish destructured-to binding nodes as vars, not args, by setting
      * pn_op to JSOP_SETLOCAL. Parser::functionDef checks for this pn_op value
      * when processing the destructuring-assignment AST prelude induced by such
      * destructuring args in Parser::functionArguments.
      *
@@ -1215,17 +1215,17 @@ BindDestructuringArg(JSContext *cx, Bind
      * destructured, and zero or more VARs (as in named local variables) for
      * the destructured-to identifiers in the property value positions within
      * the object or array destructuring pattern, and all ARGs for the formal
      * parameter list bound as locals before any VAR for a destructured name.
      */
     pn->setOp(JSOP_SETLOCAL);
     pn->pn_dflags |= PND_BOUND;
 
-    return Define(pn, atom, tc);
+    return Define(pn, name, tc);
 }
 #endif /* JS_HAS_DESTRUCTURING */
 
 bool
 Parser::functionArguments(ParseNode **listp, bool &hasRest)
 {
     if (tokenStream.getToken() != TOK_LP) {
         reportError(NULL, JSMSG_PAREN_BEFORE_FORMAL);
@@ -2015,40 +2015,40 @@ ReportRedeclaration(JSContext *cx, Parse
  * must already be in such a scope.
  *
  * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
  * property for the new variable on the block object, tc->blockChain;
  * populate data->pn->pn_{op,cookie,defn,dflags}; and stash a pointer to
  * data->pn in a slot of the block object.
  */
 static bool
-BindLet(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
+BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
     TreeContext *tc = parser->tc;
     ParseNode *pn = data->pn;
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
     Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj);
     unsigned blockCount = blockObj->slotCount();
     if (blockCount == JS_BIT(16)) {
         parser->reportError(pn, data->let.overflow);
         return false;
     }
 
     /*
      * For bindings that are hoisted to the beginning of the block/function,
      * Define() right now. For the rest, delay Define() until PushLetScope.
      */
     if (data->let.varContext == HoistVars) {
         JS_ASSERT(!tc->atBodyLevel());
-        Definition *dn = tc->decls.lookupFirst(atom);
+        Definition *dn = tc->decls.lookupFirst(name);
         if (dn && dn->pn_blockid == tc->blockid())
-            return ReportRedeclaration(cx, parser, pn, dn->isConst(), atom);
-        if (!Define(pn, atom, tc, true))
+            return ReportRedeclaration(cx, parser, pn, dn->isConst(), name);
+        if (!Define(pn, name, tc, true))
             return false;
     }
 
     /*
      * Assign block-local index to pn->pn_cookie right away, encoding it as an
      * upvar cookie whose skip tells the current static level. The emitter will
      * adjust the node's slot based on its stack depth model -- and, for global
      * and eval code, js::frontend::CompileScript will adjust the slot
@@ -2059,21 +2059,21 @@ BindLet(JSContext *cx, BindData *data, J
         return false;
     pn->pn_dflags |= PND_LET | PND_BOUND;
 
     /*
      * Define the let binding's property before storing pn in the the binding's
      * slot indexed by blockCount off the class-reserved slot base.
      */
     bool redeclared;
-    RootedId id(cx, AtomToId(atom));
+    RootedId id(cx, NameToId(name));
     Shape *shape = StaticBlockObject::addVar(cx, blockObj, id, blockCount, &redeclared);
     if (!shape) {
         if (redeclared)
-            ReportRedeclaration(cx, parser, pn, false, atom);
+            ReportRedeclaration(cx, parser, pn, false, name);
         return false;
     }
 
     /* Store pn in the static block object. */
     blockObj->setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
     return true;
 }
 
@@ -2158,42 +2158,40 @@ BindFunctionLocal(JSContext *cx, BindDat
     } else {
         JS_ASSERT(bi->kind == VARIABLE || bi->kind == CONSTANT);
     }
 
     return true;
 }
 
 static bool
-BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom_, Parser *parser)
+BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
-    RootedAtom atom(cx, atom_);
-
     TreeContext *tc = parser->tc;
     ParseNode *pn = data->pn;
 
     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
     pn->setOp(JSOP_NAME);
 
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
-    StmtInfoTC *stmt = LexicalLookup(tc, atom, NULL, (StmtInfoTC *)NULL);
+    StmtInfoTC *stmt = LexicalLookup(tc, name, NULL, (StmtInfoTC *)NULL);
 
     if (stmt && stmt->type == STMT_WITH) {
         pn->pn_dflags |= PND_DEOPTIMIZED;
         tc->sc->setFunMightAliasLocals();
         return true;
     }
 
-    DefinitionList::Range defs = tc->decls.lookupMulti(atom);
+    DefinitionList::Range defs = tc->decls.lookupMulti(name);
     JS_ASSERT_IF(stmt, !defs.empty());
 
     if (defs.empty()) {
-        if (!Define(pn, atom, tc))
+        if (!Define(pn, name, tc))
             return false;
 
         if (data->op == JSOP_DEFCONST)
             pn->pn_dflags |= PND_CONST;
 
         if (tc->sc->inFunction())
             return BindFunctionLocal(cx, data, defs, tc);
 
@@ -2205,42 +2203,42 @@ BindVarOrConst(JSContext *cx, BindData *
      * disallows several forms of redeclaration. Critically,
      *   let (x) { var x; } // error
      * is not allowed which allows us to turn any non-error redeclaration
      * into a use of the initial declaration.
      */
     Definition *dn = defs.front();
     Definition::Kind dn_kind = dn->kind();
     if (dn_kind == Definition::ARG) {
-        JSAutoByteString name;
-        if (!js_AtomToPrintableString(cx, atom, &name))
+        JSAutoByteString bytes;
+        if (!js_AtomToPrintableString(cx, name, &bytes))
             return false;
 
         if (data->op == JSOP_DEFCONST) {
-            parser->reportError(pn, JSMSG_REDECLARED_PARAM, name.ptr());
+            parser->reportError(pn, JSMSG_REDECLARED_PARAM, bytes.ptr());
             return false;
         }
-        if (!parser->reportStrictWarning(pn, JSMSG_VAR_HIDES_ARG, name.ptr()))
+        if (!parser->reportStrictWarning(pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
             return false;
     } else {
         bool error = (data->op == JSOP_DEFCONST ||
                       dn_kind == Definition::CONST ||
                       (dn_kind == Definition::LET &&
-                       (stmt->type != STMT_CATCH || OuterLet(tc, stmt, atom))));
+                       (stmt->type != STMT_CATCH || OuterLet(tc, stmt, name))));
 
         if (cx->hasStrictOption()
             ? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR
             : error)
         {
-            JSAutoByteString name;
+            JSAutoByteString bytes;
             Parser::Reporter reporter =
                 error ? &Parser::reportError : &Parser::reportStrictWarning;
-            if (!js_AtomToPrintableString(cx, atom, &name) ||
+            if (!js_AtomToPrintableString(cx, name, &bytes) ||
                 !(parser->*reporter)(pn, JSMSG_REDECLARED_VAR,
-                                     Definition::kindString(dn_kind), name.ptr()))
+                                     Definition::kindString(dn_kind), bytes.ptr()))
             {
                 return false;
             }
         }
     }
 
     LinkUseToDef(pn, dn);
     return true;
@@ -2324,18 +2322,20 @@ NoteNameUse(ParseNode *pn, Parser *parse
 
 #if JS_HAS_DESTRUCTURING
 
 static bool
 BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, Parser *parser)
 {
     JS_ASSERT(pn->isKind(PNK_NAME));
 
+    RootedPropertyName name(cx, pn->pn_atom->asPropertyName());
+
     data->pn = pn;
-    if (!data->binder(cx, data, pn->pn_atom, parser))
+    if (!data->binder(cx, data, name, parser))
         return false;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
      */
     if (pn->pn_dflags & PND_BOUND)
         pn->setOp(JSOP_SETLOCAL);
@@ -3432,17 +3432,17 @@ Parser::tryStatement()
                 pn3 = destructuringExpr(&data, tt);
                 if (!pn3)
                     return NULL;
                 break;
 #endif
 
               case TOK_NAME:
               {
-                JSAtom *label = tokenStream.currentToken().name();
+                RootedPropertyName label(context, tokenStream.currentToken().name());
                 pn3 = NewBindingNode(label, this);
                 if (!pn3)
                     return NULL;
                 data.pn = pn3;
                 if (!data.binder(context, &data, label, this))
                     return NULL;
                 break;
               }
@@ -4143,17 +4143,17 @@ Parser::variables(ParseNodeKind kind, St
 #endif /* JS_HAS_DESTRUCTURING */
 
         if (tt != TOK_NAME) {
             if (tt != TOK_ERROR)
                 reportError(NULL, JSMSG_NO_VARIABLE_NAME);
             return NULL;
         }
 
-        PropertyName *name = tokenStream.currentToken().name();
+        RootedPropertyName name(context, tokenStream.currentToken().name());
         pn2 = NewBindingNode(name, this, varContext);
         if (!pn2)
             return NULL;
         if (data.op == JSOP_DEFCONST)
             pn2->pn_dflags |= PND_CONST;
         data.pn = pn2;
         if (!data.binder(context, &data, name, this))
             return NULL;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -322,17 +322,17 @@ Parser::reportStrictModeError(ParseNode 
     va_list args;
     va_start(args, errorNumber);
     bool result = tokenStream.reportStrictModeErrorNumberVA(pn, errorNumber, args);
     va_end(args);
     return result;
 }
 
 bool
-DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser);
+DefineArg(ParseNode *pn, HandlePropertyName name, unsigned i, Parser *parser);
 
 } /* namespace frontend */
 } /* namespace js */
 
 /*
  * Convenience macro to access Parser.tokenStream as a pointer.
  */
 #define TS(p) (&(p)->tokenStream)
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1241,27 +1241,26 @@ TokenStream::getAtSourceMappingURL()
                c && c != jschar(EOF))
             tokenbuf.append(c);
 
         if (tokenbuf.empty())
             /* The source map's URL was missing, but not quite an exception that
              * we should stop and drop everything for, though. */
             return true;
 
-        int len = tokenbuf.length();
+        size_t sourceMapLength = tokenbuf.length();
 
         if (sourceMap)
             cx->free_(sourceMap);
-        sourceMap = (jschar *) cx->malloc_(sizeof(jschar) * (len + 1));
+        sourceMap = static_cast<jschar *>(cx->malloc_(sizeof(jschar) * (sourceMapLength + 1)));
         if (!sourceMap)
             return false;
 
-        for (int i = 0; i < len; i++)
-            sourceMap[i] = tokenbuf[i];
-        sourceMap[len] = '\0';
+        PodCopy(sourceMap, tokenbuf.begin(), sourceMapLength);
+        sourceMap[sourceMapLength] = '\0';
     }
     return true;
 }
 
 Token *
 TokenStream::newToken(ptrdiff_t adjust)
 {
     cursor = (cursor + 1) & ntokensMask;
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -674,21 +674,26 @@ class TokenStream
     }
 
 
     /*
      * Return the offset into the source buffer of the end of the token.
      */
     size_t endOffset(const Token &tok);
 
+    bool hasSourceMap() const {
+        return sourceMap != NULL;
+    }
+
     /*
      * Give up responsibility for managing the sourceMap filename's memory.
      */
-    const jschar *releaseSourceMap() {
-        const jschar* sm = sourceMap;
+    jschar *releaseSourceMap() {
+        JS_ASSERT(hasSourceMap());
+        jschar *sm = sourceMap;
         sourceMap = NULL;
         return sm;
     }
 
     /*
      * If the name at s[0:length] is not a keyword in this version, return
      * true with *ttp and *topp unchanged.
      *
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -308,25 +308,32 @@ static void
 FormatPhaseTimes(StatisticsSerializer &ss, const char *name, int64_t *times)
 {
     ss.beginObject(name);
     for (unsigned i = 0; phases[i].name; i++)
         ss.appendIfNonzeroMS(phases[i].name, t(times[phases[i].index]));
     ss.endObject();
 }
 
+void
+Statistics::gcDuration(int64_t *total, int64_t *maxPause)
+{
+    *total = *maxPause = 0;
+    for (SliceData *slice = slices.begin(); slice != slices.end(); slice++) {
+        *total += slice->duration();
+        if (slice->duration() > *maxPause)
+            *maxPause = slice->duration();
+    }
+}
+
 bool
 Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
 {
-    int64_t total = 0, longest = 0;
-    for (SliceData *slice = slices.begin(); slice != slices.end(); slice++) {
-        total += slice->duration();
-        if (slice->duration() > longest)
-            longest = slice->duration();
-    }
+    int64_t total, longest;
+    gcDuration(&total, &longest);
 
     double mmu20 = computeMMU(20 * PRMJ_USEC_PER_MSEC);
     double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
 
     ss.beginObject(NULL);
     if (ss.isJSON())
         ss.appendNumber("Timestamp", "%llu", "", (unsigned long long)timestamp);
     ss.appendDecimal("Total Time", "ms", t(total));
@@ -446,36 +453,33 @@ Statistics::~Statistics()
             }
         }
 
         if (fp != stdout && fp != stderr)
             fclose(fp);
     }
 }
 
-int64_t
-Statistics::gcDuration()
-{
-    return slices.back().end - slices[0].start;
-}
-
 void
 Statistics::printStats()
 {
     if (fullFormat) {
         StatisticsSerializer ss(StatisticsSerializer::AsText);
         formatData(ss, 0);
         char *msg = ss.finishCString();
         if (msg) {
             fprintf(fp, "GC(T+%.3fs) %s\n", t(slices[0].start - startupTime) / 1000.0, msg);
             js_free(msg);
         }
     } else {
+        int64_t total, longest;
+        gcDuration(&total, &longest);
+
         fprintf(fp, "%f %f %f\n",
-                t(gcDuration()),
+                t(total),
                 t(phaseTimes[PHASE_MARK]),
                 t(phaseTimes[PHASE_SWEEP]));
     }
     fflush(fp);
 }
 
 void
 Statistics::beginGC()
@@ -496,20 +500,26 @@ Statistics::endGC()
 {
     Probes::GCEnd();
     crash::SnapshotGCStack();
 
     for (int i = 0; i < PHASE_LIMIT; i++)
         phaseTotals[i] += phaseTimes[i];
 
     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
+        int64_t total, longest;
+        gcDuration(&total, &longest);
+
         (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, collectedCount == compartmentCount ? 0 : 1);
-        (*cb)(JS_TELEMETRY_GC_MS, t(gcDuration()));
+        (*cb)(JS_TELEMETRY_GC_MS, t(total));
+        (*cb)(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest));
         (*cb)(JS_TELEMETRY_GC_MARK_MS, t(phaseTimes[PHASE_MARK]));
         (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_SWEEP]));
+        (*cb)(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(phaseTimes[PHASE_MARK_ROOTS]));
+        (*cb)(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_MARK_GRAY]));
         (*cb)(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason);
         (*cb)(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gcIncrementalEnabled);
 
         double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
         (*cb)(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
     }
 
     if (fp)
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -132,17 +132,17 @@ struct Statistics {
     unsigned int counts[STAT_LIMIT];
 
     /* Allocated space before the GC started. */
     size_t preBytes;
 
     void beginGC();
     void endGC();
 
-    int64_t gcDuration();
+    void gcDuration(int64_t *total, int64_t *maxPause);
     void printStats();
     bool formatData(StatisticsSerializer &ss, uint64_t timestamp);
 
     double computeMMU(int64_t resolution);
 };
 
 struct AutoGCSlice {
     AutoGCSlice(Statistics &stats, int collectedCount, int compartmentCount, gcreason::Reason reason
--- a/js/src/jit-test/tests/sunspider/check-crypto-md5.js
+++ b/js/src/jit-test/tests/sunspider/check-crypto-md5.js
@@ -278,10 +278,15 @@ And, Montague, come you this afternoon,\
 To know our further pleasure in this case,\n\
 To old Free-town, our common judgment-place.\n\
 Once more, on pain of death, all men depart."
 
 for (var i = 0; i <4; i++) {
     plainText += plainText;
 }
 
+// root checks performed during integer conversion operations can poison
+// crypto integers in this test.
+if (relaxRootChecks)
+  relaxRootChecks();
+
 var md5Output = hex_md5(plainText);
 assertEq(md5Output, "a831e91e0f70eddcb70dc61c6f82f6cd")
--- a/js/src/jit-test/tests/sunspider/check-crypto-sha1.js
+++ b/js/src/jit-test/tests/sunspider/check-crypto-sha1.js
@@ -216,10 +216,15 @@ Which, but their children's end, nought 
 Is now the two hours' traffic of our stage;\n\
 The which if you with patient ears attend,\n\
 What here shall miss, our toil shall strive to mend.";
 
 for (var i = 0; i <4; i++) {
     plainText += plainText;
 }
 
+// root checks performed during integer conversion operations can poison
+// crypto integers in this test.
+if (relaxRootChecks)
+  relaxRootChecks();
+
 var sha1Output = hex_sha1(plainText);
 assertEq(sha1Output, "2524d264def74cce2498bf112bedf00e6c0b796d")
--- a/js/src/jsapi-tests/testXDR.cpp
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -3,16 +3,17 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "tests.h"
 #include "jsscript.h"
+#include "jsstr.h"
 
 static JSScript *
 CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JS::HandleObject obj,
                                         JSPrincipals *principals, JSPrincipals *originPrincipals,
                                         const char *bytes, size_t nbytes,
                                         const char *filename, unsigned lineno,
                                         JSVersion version)
 {
@@ -249,8 +250,45 @@ BEGIN_TEST(testXDR_source)
         CHECK(out);
         JSBool equal;
         CHECK(JS_StringEqualsAscii(cx, out, *s, &equal));
         CHECK(equal);
     }
     return true;
 }
 END_TEST(testXDR_source)
+
+BEGIN_TEST(testXDR_sourceMap)
+{
+    const char *sourceMaps[] = {
+        "http://example.com/source-map.json",
+        "file:///var/source-map.json",
+        NULL
+    };
+    for (const char **sm = sourceMaps; *sm; sm++) {
+        JSScript *script = JS_CompileScript(cx, global, "", 0, __FILE__, __LINE__);
+        CHECK(script);
+
+        size_t len = strlen(*sm);
+        jschar *expected = js::InflateString(cx, *sm, &len);
+        CHECK(expected);
+
+        // The script source takes responsibility of free'ing |expected|.
+        script->scriptSource()->setSourceMap(expected);
+        script = FreezeThaw(cx, script);
+        CHECK(script);
+        CHECK(script->scriptSource());
+        CHECK(script->scriptSource()->hasSourceMap());
+
+        const jschar *actual = script->scriptSource()->sourceMap();
+        CHECK(actual);
+
+        while (*expected) {
+            CHECK(*actual);
+            CHECK(*expected == *actual);
+            expected++;
+            actual++;
+        }
+        CHECK(!*actual);
+    }
+    return true;
+}
+END_TEST(testXDR_sourceMap)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -591,37 +591,39 @@ JS_ValueToInt64(JSContext *cx, jsval v, 
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint64(JSContext *cx, jsval v, uint64_t *ip)
 {
     RootedValue value(cx, v);
     return JS::ToUint64(cx, value, ip);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip)
-{
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
+JS_ValueToInt32(JSContext *cx, jsval vArg, int32_t *ip)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+
+    RootedValue v(cx, vArg);
     assertSameCompartment(cx, v);
 
     if (v.isInt32()) {
         *ip = v.toInt32();
         return true;
     }
 
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else if (!ToNumberSlow(cx, v, &d)) {
         return false;
     }
 
     if (MOZ_DOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
         js_ReportValueError(cx, JSMSG_CANT_CONVERT,
-                            JSDVG_SEARCH_STACK, v, NULL);
+                            JSDVG_SEARCH_STACK, v, NullPtr());
         return false;
     }
 
     *ip = (int32_t) floor(d + 0.5);  /* Round to nearest */
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -2294,17 +2296,17 @@ JS_GetGlobalForCompartmentOrNull(JSConte
     AssertHeapIsIdleOrIterating(cx);
     assertSameCompartment(cx, c);
     return c->maybeGlobal();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForScopeChain(JSContext *cx)
 {
-    AssertHeapIsIdle(cx);
+    AssertHeapIsIdleOrIterating(cx);
     CHECK_REQUEST(cx);
     return GetGlobalForScopeChain(cx);
 }
 
 JS_PUBLIC_API(jsval)
 JS_ComputeThis(JSContext *cx, jsval *vp)
 {
     AssertHeapIsIdle(cx);
@@ -4952,22 +4954,24 @@ JS_BindCallable(JSContext *cx, JSObject 
     RootedObject target(cx, targetArg);
     RootedValue thisArg(cx, ObjectValue(*newThis));
     return js_fun_bind(cx, target, thisArg, NULL, 0);
 }
 
 JSBool
 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     JSFunctionSpec *fs = (JSFunctionSpec *)
         vp->toObject().toFunction()->getExtendedSlot(0).toPrivate();
     JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
 
     if (argc < 1) {
-        js_ReportMissingArg(cx, *vp, 0);
+        js_ReportMissingArg(cx, args.calleev(), 0);
         return JS_FALSE;
     }
 
     /*
      * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
      * which is almost always the class constructor object, e.g. Array.  Then
      * call the corresponding prototype native method with our first argument
      * passed as |this|.
@@ -5913,18 +5917,18 @@ JS_New(JSContext *cx, JSObject *ctorArg,
     // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
     // is not a simple variation of JSOP_CALL. We have to determine what class
     // of object to create, create it, and clamp the return value to an object,
     // among other details. InvokeConstructor does the hard work.
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return NULL;
 
-    args.calleev().setObject(*ctor);
-    args.thisv().setNull();
+    args.setCallee(ObjectValue(*ctor));
+    args.setThis(NullValue());
     PodCopy(args.array(), argv, argc);
 
     if (!InvokeConstructor(cx, args))
         return NULL;
 
     if (!args.rval().isObject()) {
         /*
          * Although constructors may return primitives (via proxies), this
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1048,25 +1048,26 @@ class JS_PUBLIC_API(AutoGCRooter) {
         XML =          -9, /* js::AutoXMLRooter */
         OBJECT =      -10, /* js::AutoObjectRooter */
         ID =          -11, /* js::AutoIdRooter */
         VALVECTOR =   -12, /* js::AutoValueVector */
         DESCRIPTOR =  -13, /* js::AutoPropertyDescriptorRooter */
         STRING =      -14, /* js::AutoStringRooter */
         IDVECTOR =    -15, /* js::AutoIdVector */
         OBJVECTOR =   -16, /* js::AutoObjectVector */
-        SCRIPTVECTOR =-17, /* js::AutoScriptVector */
-        PROPDESC =    -18, /* js::PropDesc::AutoRooter */
-        SHAPERANGE =  -19, /* js::Shape::Range::AutoRooter */
-        STACKSHAPE =  -20, /* js::StackShape::AutoRooter */
-        STACKBASESHAPE=-21,/* js::StackBaseShape::AutoRooter */
-        BINDINGS =    -22, /* js::Bindings::AutoRooter */
-        GETTERSETTER =-23, /* js::AutoRooterGetterSetter */
-        REGEXPSTATICS=-24, /* js::RegExpStatics::AutoRooter */
-        HASHABLEVALUE=-25
+        STRINGVECTOR =-17, /* js::AutoStringVector */
+        SCRIPTVECTOR =-18, /* js::AutoScriptVector */
+        PROPDESC =    -19, /* js::PropDesc::AutoRooter */
+        SHAPERANGE =  -20, /* js::Shape::Range::AutoRooter */
+        STACKSHAPE =  -21, /* js::StackShape::AutoRooter */
+        STACKBASESHAPE=-22,/* js::StackBaseShape::AutoRooter */
+        BINDINGS =    -23, /* js::Bindings::AutoRooter */
+        GETTERSETTER =-24, /* js::AutoRooterGetterSetter */
+        REGEXPSTATICS=-25, /* js::RegExpStatics::AutoRooter */
+        HASHABLEVALUE=-26
     };
 
   private:
     AutoGCRooter ** const stackTop;
 
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE;
     void operator=(AutoGCRooter &ida) MOZ_DELETE;
@@ -1250,16 +1251,17 @@ class AutoVectorRooter : protected AutoG
     explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag
                               JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     size_t length() const { return vector.length(); }
+    bool empty() const { return vector.empty(); }
 
     bool append(const T &v) { return vector.append(v); }
     bool append(const AutoVectorRooter<T> &other) {
         return vector.append(other.vector);
     }
 
     /* For use when space has already been reserved. */
     void infallibleAppend(const T &v) { vector.infallibleAppend(v); }
@@ -1376,32 +1378,43 @@ class CallReceiver
     void clearUsedRval() const {}
 #endif
     Value *argv_;
   public:
     friend CallReceiver CallReceiverFromVp(Value *);
     friend CallReceiver CallReceiverFromArgv(Value *);
     Value *base() const { return argv_ - 2; }
     JSObject &callee() const { JS_ASSERT(!usedRval_); return argv_[-2].toObject(); }
-    Value &calleev() const { JS_ASSERT(!usedRval_); return argv_[-2]; }
-    Value &thisv() const { return argv_[-1]; }
+
+    JS::HandleValue calleev() const {
+        JS_ASSERT(!usedRval_);
+        return JS::HandleValue::fromMarkedLocation(&argv_[-2]);
+    }
+
+    JS::HandleValue thisv() const {
+        return JS::HandleValue::fromMarkedLocation(&argv_[-1]);
+    }
 
     JS::MutableHandleValue rval() const {
         setUsedRval();
         return JS::MutableHandleValue::fromMarkedLocation(&argv_[-2]);
     }
 
     Value *spAfterCall() const {
         setUsedRval();
         return argv_ - 1;
     }
 
-    void setCallee(Value calleev) {
+    void setCallee(Value calleev) const {
         clearUsedRval();
-        this->calleev() = calleev;
+        argv_[-2] = calleev;
+    }
+
+    void setThis(Value thisv) const {
+        argv_[-1] = thisv;
     }
 };
 
 JS_ALWAYS_INLINE CallReceiver
 CallReceiverFromArgv(Value *argv)
 {
     CallReceiver receiver;
     receiver.clearUsedRval();
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1530,17 +1530,17 @@ class AutoArrayCycleDetector
 static bool
 array_join_sub(JSContext *cx, CallArgs &args, bool locale)
 {
     // This method is shared by Array.prototype.join and
     // Array.prototype.toLocaleString. The steps in ES5 are nearly the same, so
     // the annotations in this function apply to both toLocaleString and join.
 
     // Step 1
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     AutoArrayCycleDetector detector(cx, obj);
     if (!detector.init())
         return false;
 
     if (detector.foundCycle()) {
@@ -1618,17 +1618,17 @@ array_join_sub(JSContext *cx, CallArgs &
                 return false;
 
             JSBool hole;
             if (!GetElement(cx, obj, index, &hole, &elt))
                 return false;
 
             if (!hole && !elt.isNullOrUndefined()) {
                 if (locale) {
-                    JSObject *robj = ToObject(cx, elt.address());
+                    JSObject *robj = ToObject(cx, elt);
                     if (!robj)
                         return false;
                     RootedId id(cx, NameToId(cx->runtime->atomState.toLocaleStringAtom));
                     if (!robj->callMethod(cx, id, 0, NULL, &elt))
                         return false;
                 }
                 if (!ValueToStringBuffer(cx, elt, sb))
                     return false;
@@ -1652,17 +1652,17 @@ array_join_sub(JSContext *cx, CallArgs &
 
 /* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
 static JSBool
 array_toString(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     RootedValue join(cx, args.calleev());
     if (!obj->getProperty(cx, cx->runtime->atomState.joinAtom, &join))
         return false;
 
     if (!js_IsCallable(join)) {
@@ -1672,18 +1672,18 @@ array_toString(JSContext *cx, unsigned a
         args.rval().setString(str);
         return true;
     }
 
     InvokeArgsGuard ag;
     if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
 
-    ag.calleev() = join;
-    ag.thisv().setObject(*obj);
+    ag.setCallee(join);
+    ag.setThis(ObjectValue(*obj));
 
     /* Do the call. */
     if (!Invoke(cx, ag))
         return false;
     args.rval().set(ag.rval());
     return true;
 }
 
@@ -1803,17 +1803,17 @@ InitArrayElements(JSContext *cx, HandleO
 
     return true;
 }
 
 static JSBool
 array_reverse(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
     do {
@@ -2073,17 +2073,17 @@ SortComparatorFunction::operator()(const
 
     if (!JS_CHECK_OPERATION_LIMIT(cx))
         return false;
 
     if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag))
         return false;
 
     ag.setCallee(fval);
-    ag.thisv() = UndefinedValue();
+    ag.setThis(UndefinedValue());
     ag[0] = a;
     ag[1] = b;
 
     if (!Invoke(cx, ag))
         return false;
 
     double cmp;
     if (!ToNumber(cx, ag.rval(), &cmp))
@@ -2113,17 +2113,17 @@ js::array_sort(JSContext *cx, unsigned a
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
             return false;
         }
         fval = args[0];     /* non-default compare function */
     } else {
         fval.setNull();
     }
 
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
     if (len == 0) {
         args.rval().setObject(*obj);
@@ -2353,17 +2353,17 @@ js_NewbornArrayPush(JSContext *cx, Handl
 {
     return NewbornArrayPushImpl(cx, obj, vp);
 }
 
 JSBool
 js::array_push(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Insist on one argument and obj of the expected class. */
     if (args.length() != 1 || !obj->isDenseArray())
         return array_push_slowly(cx, obj, args);
 
     return array_push1_dense(cx, obj, args);
@@ -2428,17 +2428,17 @@ array_pop_dense(JSContext *cx, HandleObj
 
     return js_SetLengthProperty(cx, obj, index);
 }
 
 JSBool
 js::array_pop(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     if (obj->isDenseArray())
         return array_pop_dense(cx, obj, args);
     return array_pop_slowly(cx, obj, args);
 }
 
 #ifdef JS_METHODJIT
@@ -2457,17 +2457,17 @@ mjit::stubs::ArrayShift(VMFrame &f)
     obj->moveDenseArrayElementsUnbarriered(0, 1, initlen);
 }
 #endif /* JS_METHODJIT */
 
 JSBool
 js::array_shift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     if (length == 0) {
@@ -2509,17 +2509,17 @@ js::array_shift(JSContext *cx, unsigned 
     }
     return js_SetLengthProperty(cx, obj, length);
 }
 
 static JSBool
 array_unshift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     double newlen = length;
@@ -2631,17 +2631,17 @@ CanOptimizeForDenseStorage(JSObject *arr
 
 /* ES5 15.4.4.12. */
 static JSBool
 array_splice(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Steps 3-4. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))