Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Tue, 14 Aug 2012 12:20:09 -0700
changeset 112978 62cc14fe2c5fd0eaaff6a10772e6b1956a71cc7c
parent 112977 e244389fbfc4e9a1b3c2c99e38f7c27d2538a8bc (current diff)
parent 107754 fb2d41f41c15acda67d298774c9e315d9aeb1f16 (diff)
child 112979 a1435f952ff1925b70746b80a5ee21ec8ad258fb
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [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 from mozilla-central.
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/components/tabview/test/browser_tabview_bug626455.js
browser/themes/winstripe/browser.css
content/base/src/nsDocument.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsGenericElement.cpp
content/canvas/src/Makefile.in
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextUtils.cpp
content/canvas/src/WebGLContextValidate.cpp
content/events/src/nsDOMTouchEvent.cpp
content/events/src/nsDOMTouchEvent.h
content/events/src/nsEventDispatcher.cpp
content/events/src/nsEventStateManager.cpp
content/events/test/Makefile.in
docshell/base/nsDocShell.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsPIDOMWindow.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
dom/src/storage/nsDOMStorage.cpp
dom/wifi/WifiWorker.js
gfx/2d/QuartzSupport.mm
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
js/src/frontend/BytecodeCompiler.cpp
js/src/gc/Statistics.h
js/src/jsapi.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdbgapi.cpp
js/src/jsfriendapi.h
js/src/jsobj.cpp
js/src/jsprvtd.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/methodjit/PolyIC.cpp
js/src/vm/String.cpp
js/src/vm/String.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/dom_quickstubs.qsconf
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/nsBidiPresUtils.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsDocumentViewer.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsObjectFrame.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsSubDocumentFrame.h
layout/generic/nsTextFrameThebes.cpp
mobile/android/base/GeckoApp.java
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/mozapps/extensions/XPIProvider.jsm
uriloader/prefetch/nsPrefetchService.cpp
view/src/nsViewManager.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
--- 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/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -9111,17 +9111,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
@@ -2795,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/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
@@ -2453,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/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/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1576,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)
@@ -4274,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.
@@ -4788,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.
@@ -4840,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;
 
@@ -4909,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.
@@ -4983,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);
@@ -5254,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);
 
@@ -7186,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");
 
@@ -9033,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()
@@ -9160,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
@@ -10668,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/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
@@ -1760,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
@@ -3395,16 +3395,27 @@ 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;
   }
 
--- 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/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/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/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/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) {
@@ -333,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/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
@@ -133,17 +133,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/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
@@ -2311,17 +2311,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);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -64,35 +64,32 @@ JSCompartment::JSCompartment(JSRuntime *
     propertyTree(thisForCtor()),
     emptyTypeObject(NULL),
     gcMallocAndFreeBytes(0),
     gcTriggerMallocAndFreeBytes(0),
     gcMallocBytes(0),
     debugModeBits(rt->debugMode ? DebugFromC : 0),
     watchpointMap(NULL),
     scriptCountsMap(NULL),
-    sourceMapMap(NULL),
     debugScriptMap(NULL)
 #ifdef JS_ION
     , ionCompartment_(NULL)
 #endif
 {
     setGCMaxMallocBytes(rt->gcMaxMallocBytes);
 }
 
 JSCompartment::~JSCompartment()
 {
-
 #ifdef JS_ION
     Foreground::delete_(ionCompartment_);
 #endif
 
     Foreground::delete_(watchpointMap);
     Foreground::delete_(scriptCountsMap);
-    Foreground::delete_(sourceMapMap);
     Foreground::delete_(debugScriptMap);
 }
 
 bool
 JSCompartment::init(JSContext *cx)
 {
     activeAnalysis = activeInference = false;
     types.init(cx);
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -424,18 +424,16 @@ struct JSCompartment
   private:
     void sweepBreakpoints(js::FreeOp *fop);
 
   public:
     js::WatchpointMap *watchpointMap;
 
     js::ScriptCountsMap *scriptCountsMap;
 
-    js::SourceMapMap *sourceMapMap;
-
     js::DebugScriptMap *debugScriptMap;
 	
 #ifdef JS_ION
   private:
     js::ion::IonCompartment *ionCompartment_;
 
   public:
     bool ensureIonCompartmentExists(JSContext *cx);
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -690,17 +690,19 @@ JS_PUBLIC_API(const char *)
 JS_GetScriptFilename(JSContext *cx, JSScript *script)
 {
     return script->filename;
 }
 
 JS_PUBLIC_API(const jschar *)
 JS_GetScriptSourceMap(JSContext *cx, JSScript *script)
 {
-    return script->hasSourceMap ? script->getSourceMap() : NULL;
+    ScriptSource *source = script->scriptSource();
+    JS_ASSERT(source);
+    return source->hasSourceMap() ? source->sourceMap() : NULL;
 }
 
 JS_PUBLIC_API(unsigned)
 JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
 {
     return script->lineno;
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -70,18 +70,21 @@ JS_IsDeadWrapper(JSObject *obj);
  */
 extern JS_FRIEND_API(void)
 JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape);
 
 enum {
     JS_TELEMETRY_GC_REASON,
     JS_TELEMETRY_GC_IS_COMPARTMENTAL,
     JS_TELEMETRY_GC_MS,
+    JS_TELEMETRY_GC_MAX_PAUSE_MS,
     JS_TELEMETRY_GC_MARK_MS,
     JS_TELEMETRY_GC_SWEEP_MS,
+    JS_TELEMETRY_GC_MARK_ROOTS_MS,
+    JS_TELEMETRY_GC_MARK_GRAY_MS,
     JS_TELEMETRY_GC_SLICE_MS,
     JS_TELEMETRY_GC_MMU_50,
     JS_TELEMETRY_GC_RESET,
     JS_TELEMETRY_GC_INCREMENTAL_DISABLED,
     JS_TELEMETRY_GC_NON_INCREMENTAL
 };
 
 typedef void
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2892,16 +2892,24 @@ JSObject::ReserveForTradeGuts(JSContext 
                               TradeGutsReserved &reserved)
 {
     /*
      * When performing multiple swaps between objects which may have different
      * numbers of fixed slots, we reserve all space ahead of time so that the
      * swaps can be performed infallibly.
      */
 
+    /*
+     * Swap prototypes on the two objects, so that TradeGuts can preserve
+     * the types of the two objects.
+     */
+    RootedObject na(cx, a), aProto(cx, a->getProto()), nb(cx, b), bProto(cx, b->getProto());
+    if (!SetProto(cx, na, bProto, false) || !SetProto(cx, nb, aProto, false))
+        return false;
+
     if (a->sizeOfThis() == b->sizeOfThis())
         return true;
 
     /*
      * If either object is native, it needs a new shape to preserve the
      * invariant that objects with the same shape have the same number of
      * inline slots. The fixed slots will be updated in place during TradeGuts.
      * Non-native objects need to be reshaped according to the new count.
@@ -3106,16 +3114,24 @@ JSObject::TradeGuts(JSContext *cx, JSObj
     types::TypeObject::writeBarrierPost(a->type_, &a->type_);
     types::TypeObject::writeBarrierPost(b->type_, &b->type_);
 #endif
 
     if (a->inDictionaryMode())
         a->lastProperty()->listp = &a->shape_;
     if (b->inDictionaryMode())
         b->lastProperty()->listp = &b->shape_;
+
+    /*
+     * Swap the object's types, to restore their initial type information.
+     * The prototypes of the objects were swapped in ReserveForTradeGuts.
+     */
+    TypeObject *tmp = a->type_;
+    a->type_ = b->type_;
+    b->type_ = tmp;
 }
 
 /*
  * Use this method with extreme caution. It trades the guts of two objects and updates
  * scope ownership. This operation is not thread-safe, just as fast array to slow array
  * transitions are inherently not thread-safe. Don't perform a swap operation on objects
  * shared across threads or, or bad things will happen. You have been warned.
  */
@@ -3731,17 +3747,16 @@ static JSClassInitializerOp lazy_prototy
 };
 
 namespace js {
 
 bool
 SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycles)
 {
     JS_ASSERT_IF(!checkForCycles, obj != proto);
-    JS_ASSERT(obj->isExtensible());
 
 #if JS_HAS_XML_SUPPORT
     if (proto && proto->isXML()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
         return false;
     }
 #endif
 
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -77,17 +77,16 @@ typedef struct JSXML                JSXM
 
 extern "C++" {
 
 class JSDependentString;
 class JSExtensibleString;
 class JSExternalString;
 class JSLinearString;
 class JSFixedString;
-class JSStaticAtom;
 class JSRope;
 class JSAtom;
 class JSWrapper;
 
 namespace js {
 
 struct ArgumentsData;
 struct Class;
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -904,71 +904,16 @@ void
 JSScript::destroyScriptCounts(FreeOp *fop)
 {
     if (hasScriptCounts) {
         ScriptCounts scriptCounts = releaseScriptCounts();
         fop->free_(scriptCounts.pcCountsVector);
     }
 }
 
-bool
-JSScript::setSourceMap(JSContext *cx, jschar *sourceMap)
-{
-    JS_ASSERT(!hasSourceMap);
-
-    /* Create compartment's sourceMapMap if necessary. */
-    SourceMapMap *map = compartment()->sourceMapMap;
-    if (!map) {
-        map = cx->new_<SourceMapMap>();
-        if (!map || !map->init()) {
-            cx->delete_(map);
-            return false;
-        }
-        compartment()->sourceMapMap = map;
-    }
-
-    if (!map->putNew(this, sourceMap))
-        return false;
-
-    hasSourceMap = true; // safe to set this;  we can't fail after this point
-
-    return true;
-}
-
-jschar *
-JSScript::getSourceMap() {
-    JS_ASSERT(hasSourceMap);
-    SourceMapMap *map = compartment()->sourceMapMap;
-    JS_ASSERT(map);
-    SourceMapMap::Ptr p = map->lookup(this);
-    JS_ASSERT(p);
-    return p->value;
-}
-
-jschar *
-JSScript::releaseSourceMap()
-{
-    JS_ASSERT(hasSourceMap);
-    SourceMapMap *map = compartment()->sourceMapMap;
-    JS_ASSERT(map);
-    SourceMapMap::Ptr p = map->lookup(this);
-    JS_ASSERT(p);
-    jschar *sourceMap = p->value;
-    map->remove(p);
-    hasSourceMap = false;
-    return sourceMap;
-}
-
-void
-JSScript::destroySourceMap(FreeOp *fop)
-{
-    if (hasSourceMap)
-        fop->free_(releaseSourceMap());
-}
-
 #ifdef JS_THREADSAFE
 void
 SourceCompressorThread::compressorThread(void *arg)
 {
     PR_SetCurrentThreadName("JS Source Compressing Thread");
     static_cast<SourceCompressorThread *>(arg)->threadLoop();
 }
 
@@ -1281,16 +1226,17 @@ SourceCompressionToken::abort()
 #endif
 }
 
 void
 ScriptSource::destroy(JSRuntime *rt)
 {
     JS_ASSERT(ready());
     rt->free_(data.compressed);
+    rt->free_(sourceMap_);
 #ifdef DEBUG
     ready_ = false;
 #endif
     rt->free_(this);
 }
 
 size_t
 ScriptSource::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf)
@@ -1343,24 +1289,64 @@ ScriptSource::performXDR(XDRState<mode> 
             }
             return false;
         }
         length_ = length;
         compressedLength_ = compressedLength;
         argumentsNotIncluded_ = argumentsNotIncluded;
     }
 
+    uint8_t haveSourceMap = hasSourceMap();
+    if (!xdr->codeUint8(&haveSourceMap))
+        return false;
+
+    if (haveSourceMap) {
+        uint32_t sourceMapLen = (mode == XDR_DECODE) ? 0 : js_strlen(sourceMap_);
+        if (!xdr->codeUint32(&sourceMapLen))
+            return false;
+
+        if (mode == XDR_DECODE) {
+            size_t byteLen = (sourceMapLen + 1) * sizeof(jschar);
+            sourceMap_ = static_cast<jschar *>(xdr->cx()->malloc_(byteLen));
+            if (!sourceMap_)
+                return false;
+        }
+        if (!xdr->codeChars(sourceMap_, sourceMapLen)) {
+            if (mode == XDR_DECODE) {
+                xdr->cx()->free_(sourceMap_);
+                sourceMap_ = NULL;
+            }
+            return false;
+        }
+        sourceMap_[sourceMapLen] = '\0';
+    }
+
 #ifdef DEBUG
     if (mode == XDR_DECODE)
         ready_ = true;
 #endif
 
     return true;
 }
 
+void
+ScriptSource::setSourceMap(jschar *sm)
+{
+    JS_ASSERT(!hasSourceMap());
+    JS_ASSERT(sm);
+    sourceMap_ = sm;
+}
+
+const jschar *
+ScriptSource::sourceMap()
+{
+    JS_ASSERT(hasSourceMap());
+    return sourceMap_;
+}
+
 /*
  * Shared script filename management.
  */
 
 const char *
 js::SaveScriptFilename(JSContext *cx, const char *filename)
 {
     if (!filename)
@@ -1745,24 +1731,16 @@ JSScript::fullyInitFromEmitter(JSContext
     }
     script->lineno = bce->firstLine;
     if (script->nfixed + bce->maxStackDepth >= JS_BIT(16)) {
         bce->reportError(NULL, JSMSG_NEED_DIET, "script");
         return false;
     }
     script->nslots = script->nfixed + bce->maxStackDepth;
 
-    jschar *sourceMap = (jschar *) bce->parser->tokenStream.releaseSourceMap();
-    if (sourceMap) {
-        if (!script->setSourceMap(cx, sourceMap)) {
-            cx->free_(sourceMap);
-            return false;
-        }
-    }
-
     if (!FinishTakingSrcNotes(cx, bce, script->notes()))
         return false;
     if (bce->ntrynotes != 0)
         FinishTakingTryNotes(bce, script->trynotes());
     if (bce->objectList.length != 0)
         bce->objectList.finish(script->objects());
     if (bce->regexpList.length != 0)
         bce->regexpList.finish(script->regexps());
@@ -1915,17 +1893,16 @@ JSScript::finalize(FreeOp *fop)
     mjit::ReleaseScriptCode(fop, this);
 # ifdef JS_ION
     if (hasIonScript())
         ion::IonScript::Destroy(fop, ion);
 # endif
 #endif
 
     destroyScriptCounts(fop);
-    destroySourceMap(fop);
     destroyDebugScript(fop);
     scriptSource_->decref(fop->runtime());
 
     if (data) {
         JS_POISON(data, 0xdb, computedSizeOfData());
         fop->free_(data);
     }
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -304,21 +304,16 @@ class ScriptCounts
     }
 };
 
 typedef HashMap<JSScript *,
                 ScriptCounts,
                 DefaultHasher<JSScript *>,
                 SystemAllocPolicy> ScriptCountsMap;
 
-typedef HashMap<JSScript *,
-                jschar *,
-                DefaultHasher<JSScript *>,
-                SystemAllocPolicy> SourceMapMap;
-
 class DebugScript
 {
     friend struct ::JSScript;
 
     /*
      * When non-zero, compile script in single-step mode. The top bit is set and
      * cleared by setStepMode, as used by JSD. The lower bits are a count,
      * adjusted by changeStepModeCount, used by the Debugger object. Only
@@ -545,18 +540,16 @@ struct JSScript : public js::gc::Cell
     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
 #endif
     bool            invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */
     bool            callDestroyHook:1;/* need to call destroy hook */
     bool            isGenerator:1;    /* is a generator */
     bool            isGeneratorExp:1; /* is a generator expression */
     bool            hasScriptCounts:1;/* script has an entry in
                                          JSCompartment::scriptCountsMap */
-    bool            hasSourceMap:1;   /* script has an entry in
-                                         JSCompartment::sourceMapMap */
     bool            hasDebugScript:1; /* script has an entry in
                                          JSCompartment::debugScriptMap */
 
   private:
     /* See comments below. */
     bool            argsHasVarBinding_:1;
     bool            needsArgsAnalysis_:1;
     bool            needsArgsObj_:1;
@@ -755,21 +748,16 @@ struct JSScript : public js::gc::Cell
 #endif
 
   public:
     bool initScriptCounts(JSContext *cx);
     js::PCCounts getPCCounts(jsbytecode *pc);
     js::ScriptCounts releaseScriptCounts();
     void destroyScriptCounts(js::FreeOp *fop);
 
-    bool setSourceMap(JSContext *cx, jschar *sourceMap);
-    jschar *getSourceMap();
-    jschar *releaseSourceMap();
-    void destroySourceMap(js::FreeOp *fop);
-
     jsbytecode *main() {
         return code + mainOffset;
     }
 
     /*
      * computedSizeOfData() is the in-use size of all the data sections.
      * sizeOfData() is the size of the block allocated to hold all the data sections
      * (which can be larger than the in-use size).
@@ -1009,31 +997,33 @@ struct ScriptSource
         // compressed holds the compressed data; otherwise, source holds the
         // uncompressed source.
         jschar *source;
         unsigned char *compressed;
     } data;
     uint32_t refs;
     uint32_t length_;
     uint32_t compressedLength_;
+    jschar *sourceMap_;
 
     // True if we can call JSRuntime::sourceHook to load the source on
     // demand. If sourceRetrievable_ and hasSourceData() are false, it is not
     // possible to get source at all.
     bool sourceRetrievable_:1;
     bool argumentsNotIncluded_:1;
 #ifdef DEBUG
     bool ready_:1;
 #endif
 
   public:
     ScriptSource()
       : refs(0),
         length_(0),
         compressedLength_(0),
+        sourceMap_(NULL),
         sourceRetrievable_(false),
         argumentsNotIncluded_(false)
 #ifdef DEBUG
        ,ready_(true)
 #endif
     {
         data.source = NULL;
     }
@@ -1065,16 +1055,21 @@ struct ScriptSource
     }
     JSFixedString *substring(JSContext *cx, uint32_t start, uint32_t stop);
     size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf);
 
     // XDR handling
     template <XDRMode mode>
     bool performXDR(XDRState<mode> *xdr);
 
+    // Source maps
+    void setSourceMap(jschar *sm);
+    const jschar *sourceMap();
+    bool hasSourceMap() const { return sourceMap_ != NULL; }
+
   private:
     void destroy(JSRuntime *rt);
     bool compressed() { return compressedLength_ != 0; }
 };
 
 class ScriptSourceHolder
 {
     JSRuntime *rt;
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -676,16 +676,24 @@ struct GetPropHelper {
         if (!prop) {
             /*
              * Just because we didn't find the property on the object doesn't
              * mean it won't magically appear through various engine hacks:
              */
             if (obj->getClass()->getProperty && obj->getClass()->getProperty != JS_PropertyStub)
                 return Lookup_Uncacheable;
 
+            /*
+             * Don't generate missing property ICs if we skipped a non-native
+             * object, as lookups may extend beyond the prototype chain (e.g.
+             * for ListBase proxies).
+             */
+            if (!obj->isNative())
+                return Lookup_Uncacheable;
+
 #if JS_HAS_NO_SUCH_METHOD
             /*
              * The __noSuchMethod__ hook may substitute in a valid method.
              * Since, if o.m is missing, o.m() will probably be an error,
              * just mark all missing callprops as uncacheable.
              */
             if (*f.pc() == JSOP_CALLPROP)
                 return Lookup_Uncacheable;
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -208,17 +208,17 @@ JSFixedString::new_(JSContext *cx, const
         return NULL;
     str->init(chars, length);
     return str;
 }
 
 JS_ALWAYS_INLINE JSAtom *
 JSFixedString::morphAtomizedStringIntoAtom()
 {
-    d.lengthAndFlags = buildLengthAndFlags(length(), NON_STATIC_ATOM_FLAGS);
+    d.lengthAndFlags = buildLengthAndFlags(length(), ATOM_FLAGS);
     return &asAtom();
 }
 
 JS_ALWAYS_INLINE JSInlineString *
 JSInlineString::new_(JSContext *cx)
 {
     return (JSInlineString *)js_NewGCString(cx);
 }
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -43,45 +43,47 @@ JSString::isExternal() const
     bool is_external = (getAllocKind() == gc::FINALIZE_EXTERNAL_STRING);
     JS_ASSERT_IF(is_external, isFixed());
     return is_external;
 }
 
 size_t
 JSString::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf)
 {
-    /* JSRope: do nothing, we'll count all children chars when we hit the leaf strings. */
+    // JSRope: do nothing, we'll count all children chars when we hit the leaf strings.
     if (isRope())
         return 0;
 
     JS_ASSERT(isLinear());
 
-    /* JSDependentString: do nothing, we'll count the chars when we hit the base string. */
+    // JSDependentString: do nothing, we'll count the chars when we hit the base string.
     if (isDependent())
         return 0;
 
     JS_ASSERT(isFlat());
 
-    /* JSExtensibleString: count the full capacity, not just the used space. */
+    // JSExtensibleString: count the full capacity, not just the used space.
     if (isExtensible()) {
         JSExtensibleString &extensible = asExtensible();
         return mallocSizeOf(extensible.chars());
     }
 
     JS_ASSERT(isFixed());
 
-    /* JSExternalString: don't count, the chars could be stored anywhere. */
+    // JSExternalString: don't count, the chars could be stored anywhere.
     if (isExternal())
         return 0;
 
-    /* JSInlineString, JSShortString, JSInlineAtom, JSShortAtom: the chars are inline. */
+    // JSInlineString, JSShortString, JSInlineAtom, JSShortAtom: the chars are inline.
     if (isInline())
         return 0;
 
-    /* JSAtom, JSFixedString: count the chars. +1 for the null char. */
+    // JSAtom, JSFixedString, JSUndependedString: measure the space for the
+    // chars.  For JSUndependedString, there is no need to count the base
+    // string, for the same reason as JSDependentString above.
     JSFixedString &fixed = asFixed();
     return mallocSizeOf(fixed.chars());
 }
 
 #ifdef DEBUG
 void
 JSString::dump()
 {
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -95,17 +95,17 @@ static const size_t UINT32_CHAR_BUFFER_L
  *  | JSDependentString          base / -
  *  |
  * JSFlatString (abstract)       - / null-terminated
  *  | \
  *  | JSExtensibleString         capacity / no external pointers into char array
  *  |
  * JSFixedString                 - / may have external pointers into char array
  *  | \  \  \
- *  |  \  \ JSUndependedString   - / original dependent base
+ *  |  \  \ JSUndependedString   original dependent base / -
  *  |   \  \
  *  |    \ JSExternalString      - / char array memory managed by embedding
  *  |     \
  *  |     JSInlineString         - / chars stored in header
  *  |      | \
  *  |      | JSShortString       - / header is fat
  *  |      |        |
  * JSAtom  |        |            - / string equality === pointer equality
@@ -163,18 +163,18 @@ class JSString : public js::gc::Cell
 
     /*
      * The low LENGTH_SHIFT bits of lengthAndFlags are used to encode the type
      * of the string. The remaining bits store the string length (which must be
      * less or equal than MAX_LENGTH).
      *
      * Instead of using a dense index to represent the most-derived type, string
      * types are encoded to allow single-op tests for hot queries (isRope,
-     * isDependent, isFlat, isAtom, isStaticAtom) which, in view of subtyping,
-     * would require slower (isX() || isY() || isZ()).
+     * isDependent, isFlat, isAtom) which, in view of subtyping, would require
+     * slower (isX() || isY() || isZ()).
      *
      * The string type encoding can be summarized as follows. The "instance
      * encoding" entry for a type specifies the flag bits used to create a
      * string instance of that type. Abstract types have no instances and thus
      * have no such entry. The "subtype predicate" entry for a type specifies
      * the predicate used to query whether a JSString instance is subtype
      * (reflexively) of that type.
      *
@@ -189,31 +189,30 @@ class JSString : public js::gc::Cell
      *   Fixed        0110       isFlat && !isExtensible
      *   Inline       0110       isFixed && (u1.chars == inlineStorage || isShort)
      *   Short        0110       header in FINALIZE_SHORT_STRING arena
      *   External     0110       header in FINALIZE_EXTERNAL_STRING arena
      *   Undepended   1010       1010
      *   Atom         1000       x000
      *   InlineAtom   1000       1000 && is Inline
      *   ShortAtom    1000       1000 && is Short
-     *   StaticAtom   0000       0000
      */
 
     static const size_t LENGTH_SHIFT          = 4;
     static const size_t FLAGS_MASK            = JS_BITMASK(LENGTH_SHIFT);
 
     static const size_t ROPE_BIT              = JS_BIT(0);
 
     static const size_t DEPENDENT_FLAGS       = JS_BIT(1);
     static const size_t EXTENSIBLE_FLAGS      = JS_BIT(2);
     static const size_t FIXED_FLAGS           = JS_BIT(1) | JS_BIT(2);
     static const size_t UNDEPENDED_FLAGS      = JS_BIT(1) | JS_BIT(3);
 
     static const size_t ATOM_MASK             = JS_BITMASK(3);
-    static const size_t NON_STATIC_ATOM_FLAGS = JS_BIT(3);
+    static const size_t ATOM_FLAGS            = JS_BIT(3);
 
     static const size_t MAX_LENGTH            = JS_BIT(32 - LENGTH_SHIFT) - 1;
 
     size_t buildLengthAndFlags(size_t length, size_t flags) {
         JS_ASSERT(length <= MAX_LENGTH);
         JS_ASSERT(flags <= FLAGS_MASK);
         return (length << LENGTH_SHIFT) | flags;
     }
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -20,17 +20,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 128);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 129);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
 
     JSContext *cx() const {
         return context;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2018,22 +2018,31 @@ AccumulateTelemetryCallback(int id, uint
         Telemetry::Accumulate(Telemetry::GC_REASON_2, sample);
         break;
       case JS_TELEMETRY_GC_IS_COMPARTMENTAL:
         Telemetry::Accumulate(Telemetry::GC_IS_COMPARTMENTAL, sample);
         break;
       case JS_TELEMETRY_GC_MS:
         Telemetry::Accumulate(Telemetry::GC_MS, sample);
         break;
+      case JS_TELEMETRY_GC_MAX_PAUSE_MS:
+        Telemetry::Accumulate(Telemetry::GC_MAX_PAUSE_MS, sample);
+        break;
       case JS_TELEMETRY_GC_MARK_MS:
         Telemetry::Accumulate(Telemetry::GC_MARK_MS, sample);
         break;
       case JS_TELEMETRY_GC_SWEEP_MS:
         Telemetry::Accumulate(Telemetry::GC_SWEEP_MS, sample);
         break;
+      case JS_TELEMETRY_GC_MARK_ROOTS_MS:
+        Telemetry::Accumulate(Telemetry::GC_MARK_ROOTS_MS, sample);
+        break;
+      case JS_TELEMETRY_GC_MARK_GRAY_MS:
+        Telemetry::Accumulate(Telemetry::GC_MARK_GRAY_MS, sample);
+        break;
       case JS_TELEMETRY_GC_SLICE_MS:
         Telemetry::Accumulate(Telemetry::GC_SLICE_MS, sample);
         break;
       case JS_TELEMETRY_GC_MMU_50:
         Telemetry::Accumulate(Telemetry::GC_MMU_50, sample);
         break;
       case JS_TELEMETRY_GC_RESET:
         Telemetry::Accumulate(Telemetry::GC_RESET, sample);
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -496,16 +496,17 @@ irregularFilenames = {
     'nsIWebGLShaderPrecisionFormat' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLActiveInfo': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLUniformLocation': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtension': 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionStandardDerivatives' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionTextureFilterAnisotropic' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionLoseContext' : 'nsIDOMWebGLRenderingContext',
     'nsIWebGLExtensionCompressedTextureS3TC' : 'nsIDOMWebGLRenderingContext',
+    'nsIWebGLExtensionDepthTexture' : 'nsIDOMWebGLRenderingContext',
 
     'nsIIndexedDatabaseUsageCallback': 'nsIIndexedDatabaseManager',
 
     'nsIDOMTouch': 'nsIDOMTouchEvent',
     'nsIDOMTouchList': 'nsIDOMTouchEvent',
 
     'nsIDOMMutationRecord': 'nsIDOMMutationObserver',
 
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2140,29 +2140,41 @@ ChooseScaleAndSetTransform(FrameLayerBui
   return result;
 }
 
 static void
 ApplyThebesLayerInvalidation(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aContainerFrame,
                              nsDisplayItem* aContainerItem,
                              ContainerState& aState,
-                             nsPoint* aCurrentOffset)
+                             nsPoint* aCurrentOffset,
+                             nsDisplayTransform* aTransform)
 {
   *aCurrentOffset = aContainerItem ? aContainerItem->ToReferenceFrame()
     : aBuilder->ToReferenceFrame(aContainerFrame);
 
   FrameProperties props = aContainerFrame->Properties();
   RefCountedRegion* invalidThebesContent = static_cast<RefCountedRegion*>
     (props.Get(ThebesLayerInvalidRegionProperty()));
   if (invalidThebesContent) {
     const FrameLayerBuilder::ContainerParameters& scaleParameters = aState.ScaleParameters();
-    aState.AddInvalidThebesContent(invalidThebesContent->mRegion.
-      ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
-                           aState.GetAppUnitsPerDevPixel()));
+    if (aTransform) {
+      // XXX We're simplifying the transform by only using the bounds of the
+      //     region. This may have performance implications.
+      nsRect transformedBounds = aTransform->
+        TransformRectOut(invalidThebesContent->mRegion.GetBounds(),
+                         aTransform->GetUnderlyingFrame(), -(*aCurrentOffset));
+      aState.AddInvalidThebesContent(transformedBounds.
+        ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
+                             aState.GetAppUnitsPerDevPixel()));
+    } else {
+      aState.AddInvalidThebesContent(invalidThebesContent->mRegion.
+        ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
+                             aState.GetAppUnitsPerDevPixel()));
+    }
     // We have to preserve the current contents of invalidThebesContent
     // because there might be multiple container layers for the same
     // frame and we need to invalidate the ThebesLayer children of all
     // of them. Also, multiple calls to ApplyThebesLayerInvalidation for the
     // same layer can share the same region.
   } else {
     // The region was deleted to indicate that everything should be
     // invalidated.
@@ -2203,16 +2215,46 @@ FrameLayerBuilder::RestoreThebesLayerIte
       aEntry->mItems.TruncateLength(i);
       return PL_DHASH_NEXT;
     }
   }
 
   return PL_DHASH_NEXT;
 }
 
+static nsDisplayTransform* FindTransformForContainerFrame(nsIFrame* aContainerFrame,
+                                                          nsDisplayItem* aContainerItem)
+{
+  if (!aContainerFrame->IsTransformed() ||
+      aContainerItem->GetType() == nsDisplayItem::TYPE_TRANSFORM)
+    return nullptr;
+
+  nsTArray<nsDisplayItem*> queue;
+  queue.AppendElement(aContainerItem);
+  while (queue.Length()) {
+    nsDisplayItem* item = queue[queue.Length() - 1];
+    queue.RemoveElementAt(queue.Length() - 1);
+
+    if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
+      return static_cast<nsDisplayTransform*>(item);
+    }
+
+    if (item->GetList()) {
+      for (nsDisplayItem* child = item->GetList()->GetBottom(); child;
+           child = child->GetAbove()) {
+        if (child->GetUnderlyingFrame() == aContainerFrame) {
+          queue.AppendElement(child);
+        }
+      }
+    }
+  }
+
+  return nullptr;
+}
+
 already_AddRefed<ContainerLayer>
 FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
                                           LayerManager* aManager,
                                           nsIFrame* aContainerFrame,
                                           nsDisplayItem* aContainerItem,
                                           const nsDisplayList& aChildren,
                                           const ContainerParameters& aParameters,
                                           const gfx3DMatrix* aTransform)
@@ -2296,19 +2338,25 @@ FrameLayerBuilder::BuildContainerLayerFo
   while (true) {
     ContainerState state(aBuilder, aManager, GetLayerBuilderForManager(aManager),
                          aContainerFrame, containerLayer, scaleParameters);
     if (flattenedLayers) {
       state.SetInvalidateAllThebesContent();
     }
 
     if (aManager == mRetainingManager) {
+      // If the container frame has a transform and it's contained in the
+      // container item's sub-tree, we need to transform the invalid region
+      // before applying it.
+      nsDisplayTransform* transformItem =
+        FindTransformForContainerFrame(aContainerFrame, aContainerItem);
+
       nsPoint currentOffset;
       ApplyThebesLayerInvalidation(aBuilder, aContainerFrame, aContainerItem, state,
-                                   &currentOffset);
+                                   &currentOffset, transformItem);
       SetHasContainerLayer(aContainerFrame, currentOffset);
 
       nsAutoTArray<nsIFrame*,4> mergedFrames;
       if (aContainerItem) {
         aContainerItem->GetMergedFrames(&mergedFrames);
       }
       for (PRUint32 i = 0; i < mergedFrames.Length(); ++i) {
         nsIFrame* mergedFrame = mergedFrames[i];
@@ -2319,17 +2367,17 @@ FrameLayerBuilder::BuildContainerLayerFo
           entry->mIsSharingContainerLayer = true;
 
           // Store the invalid region property in case this frame is represented
           // by multiple container layers. This is cleared and set when iterating
           // over the DisplayItemDataEntry's in WillEndTransaction.
           entry->mInvalidRegion = thebesLayerInvalidRegion;
         }
         ApplyThebesLayerInvalidation(aBuilder, mergedFrame, nullptr, state,
-                                     &currentOffset);
+                                     &currentOffset, transformItem);
         SetHasContainerLayer(mergedFrame, currentOffset);
       }
     }
 
     Clip clip;
     state.ProcessDisplayItems(aChildren, clip, stateFlags);
 
     // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -234,16 +234,17 @@ public:
                          LayerManager* aManager,
                          nsDisplayItem* aItem);
 
   /**
    * Call this during invalidation if aFrame has
    * the NS_FRAME_HAS_CONTAINER_LAYER state bit. Only the nearest
    * ancestor frame of the damaged frame that has
    * NS_FRAME_HAS_CONTAINER_LAYER needs to be invalidated this way.
+   * It is assumed that aRect does NOT have the frame's transforms applied.
    */
   static void InvalidateThebesLayerContents(nsIFrame* aFrame,
                                             const nsRect& aRect);
 
   /**
    * For any descendant frame of aFrame (including across documents) that
    * has an associated container layer, invalidate all the contents of
    * all ThebesLayer children of the container. Useful when aFrame is
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -416,45 +416,46 @@ SplitInlineAncestors(nsIFrame* aParent,
   nsIFrame* frame = aFrame;
   nsIFrame* parent = aParent;
   nsIFrame* newParent;
 
   while (IsBidiSplittable(parent)) {
     nsIFrame* grandparent = parent->GetParent();
     NS_ASSERTION(grandparent, "Couldn't get parent's parent in nsBidiPresUtils::SplitInlineAncestors");
     
-    nsresult rv = presShell->FrameConstructor()->
-      CreateContinuingFrame(presContext, parent, grandparent, &newParent, false);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-    
     // Split the child list after |frame|, unless it is the last child.
     if (!frame || frame->GetNextSibling()) {
+    
+      nsresult rv = presShell->FrameConstructor()->
+        CreateContinuingFrame(presContext, parent, grandparent, &newParent, false);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
       nsContainerFrame* container = do_QueryFrame(parent);
       nsFrameList tail = container->StealFramesAfter(frame);
 
       // Reparent views as necessary
       rv = nsContainerFrame::ReparentFrameViewList(presContext, tail, parent, newParent);
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       // The parent's continuation adopts the siblings after the split.
       rv = newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nullptr, tail);
       if (NS_FAILED(rv)) {
         return rv;
       }
-    }
     
-    // The list name kNoReflowPrincipalList would indicate we don't want reflow
-    nsFrameList temp(newParent, newParent);
-    rv = grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
-    if (NS_FAILED(rv)) {
-      return rv;
+      // The list name kNoReflowPrincipalList would indicate we don't want reflow
+      nsFrameList temp(newParent, newParent);
+      rv = grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
     }
     
     frame = parent;
     parent = grandparent;
   }
   
   return NS_OK;
 }
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2242,17 +2242,17 @@ bool nsDisplayWrapList::ChildrenCanBeIna
     if (f) {
       nsIFrame* activeScrolledRoot =
         nsLayoutUtils::GetActiveScrolledRootFor(f, nullptr);
       if (activeScrolledRoot != aActiveScrolledRoot)
         return false;
     }
 
     LayerState state = i->GetLayerState(aBuilder, aManager, aParameters);
-    if (state == LAYER_ACTIVE)
+    if (state == LAYER_ACTIVE || state == LAYER_ACTIVE_FORCE)
       return false;
     if (state == LAYER_NONE) {
       nsDisplayList* list = i->GetList();
       if (list && !ChildrenCanBeInactive(aBuilder, aManager, aParameters, *list, aActiveScrolledRoot))
         return false;
     }
   }
   return true;
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2428,17 +2428,17 @@ private:
  * The default value for both edges is zero, which means everything is painted.
  */
 class nsCharClipDisplayItem : public nsDisplayItem {
 public:
   nsCharClipDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame), mLeftEdge(0), mRightEdge(0) {}
 
   nsCharClipDisplayItem(nsIFrame* aFrame)
-    : nsDisplayItem(nsnull, aFrame, nsPoint()) {}
+    : nsDisplayItem(nullptr, aFrame, nsPoint()) {}
 
   struct ClipEdges {
     ClipEdges(const nsDisplayItem& aItem,
               nscoord aLeftEdge, nscoord aRightEdge) {
       nsRect r = aItem.GetUnderlyingFrame()->GetScrollableOverflowRect() +
                  aItem.ToReferenceFrame();
       mX = aLeftEdge > 0 ? r.x + aLeftEdge : nscoord_MIN;
       mXMost = aRightEdge > 0 ? NS_MAX(r.XMost() - aRightEdge, mX) : nscoord_MAX;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -4305,16 +4305,23 @@ DocumentViewerImpl::GetHistoryEntry(nsIS
 
 NS_IMETHODIMP
 DocumentViewerImpl::GetIsTabModalPromptAllowed(bool *aAllowed)
 {
   *aAllowed = !(mInPermitUnload || mHidden);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+DocumentViewerImpl::GetIsHidden(bool *aHidden)
+{
+  *aHidden = mHidden;
+  return NS_OK;
+}
+
 void
 DocumentViewerImpl::DestroyPresShell()
 {
   // Break circular reference (or something)
   mPresShell->EndObservingDocument();
 
   nsCOMPtr<nsISelection> selection;
   GetDocumentSelection(getter_AddRefs(selection));
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2470,41 +2470,45 @@ nsRootPresContext::~nsRootPresContext()
 {
   NS_ASSERTION(mRegisteredPlugins.Count() == 0,
                "All plugins should have been unregistered");
   CancelDidPaintTimer();
   CancelUpdatePluginGeometryTimer();
 }
 
 void
-nsRootPresContext::RegisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
+nsRootPresContext::RegisterPluginForGeometryUpdates(nsIContent* aPlugin)
 {
   mRegisteredPlugins.PutEntry(aPlugin);
 }
 
 void
-nsRootPresContext::UnregisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
+nsRootPresContext::UnregisterPluginForGeometryUpdates(nsIContent* aPlugin)
 {
   mRegisteredPlugins.RemoveEntry(aPlugin);
 }
 
 struct PluginGeometryClosure {
   nsIFrame* mRootFrame;
   PRInt32   mRootAPD;
   nsIFrame* mChangedSubtree;
   nsRect    mChangedRect;
   nsTHashtable<nsPtrHashKey<nsObjectFrame> > mAffectedPlugins;
   nsRect    mAffectedPluginBounds;
   nsTArray<nsIWidget::Configuration>* mOutputConfigurations;
 };
 static PLDHashOperator
-PluginBoundsEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
+PluginBoundsEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
 {
   PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
-  nsObjectFrame* f = aEntry->GetKey();
+  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
+  if (!f) {
+    NS_WARNING("Null frame in PluginBoundsEnumerator");
+    return PL_DHASH_NEXT;
+  }
   nsRect fBounds = f->GetContentRect() +
       f->GetParent()->GetOffsetToCrossDoc(closure->mRootFrame);
   PRInt32 APD = f->PresContext()->AppUnitsPerDevPixel();
   fBounds = fBounds.ConvertAppUnitsRoundOut(APD, closure->mRootAPD);
   // We're identifying the plugins that may have been affected by changes
   // to the frame subtree rooted at aChangedRoot. Any plugin that overlaps
   // the overflow area of aChangedRoot could have its clip region affected
   // because it might be covered (or uncovered) by changes to the subtree.
@@ -2775,19 +2779,23 @@ nsRootPresContext::RequestUpdatePluginGe
       return;
     mUpdatePluginGeometryForFrame->PresContext()->
       SetContainsUpdatePluginGeometryFrame(false);
     mUpdatePluginGeometryForFrame = nullptr;
   }
 }
 
 static PLDHashOperator
-PluginDidSetGeometryEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
+PluginDidSetGeometryEnumerator(nsRefPtrHashKey<nsIContent>* aEntry, void* userArg)
 {
-  nsObjectFrame* f = aEntry->GetKey();
+  nsObjectFrame* f = static_cast<nsObjectFrame*>(aEntry->GetKey()->GetPrimaryFrame());
+  if (!f) {
+    NS_WARNING("Null frame in PluginDidSetGeometryEnumerator");
+    return PL_DHASH_NEXT;
+  }
   f->DidSetWidgetGeometry();
   return PL_DHASH_NEXT;
 }
 
 void
 nsRootPresContext::DidApplyPluginGeometryUpdates()
 {
   mRegisteredPlugins.EnumerateEntries(PluginDidSetGeometryEnumerator, nullptr);
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1271,23 +1271,23 @@ public:
   }
 
   /**
    * Registers a plugin to receive geometry updates (position and clip
    * region) so it can update its widget.
    * Callers must call UnregisterPluginForGeometryUpdates before
    * the aPlugin frame is destroyed.
    */
-  void RegisterPluginForGeometryUpdates(nsObjectFrame* aPlugin);
+  void RegisterPluginForGeometryUpdates(nsIContent* aPlugin);
   /**
    * Stops a plugin receiving geometry updates (position and clip
    * region). If the plugin was not already registered, this does
    * nothing.
    */
-  void UnregisterPluginForGeometryUpdates(nsObjectFrame* aPlugin);
+  void UnregisterPluginForGeometryUpdates(nsIContent* aPlugin);
 
   /**
    * Iterate through all plugins that are registered for geometry updates
    * and update their position and clip region to match the current frame
    * tree.
    */
   void UpdatePluginGeometry();
 
@@ -1381,17 +1381,17 @@ protected:
     if (mUpdatePluginGeometryTimer) {
       mUpdatePluginGeometryTimer->Cancel();
       mUpdatePluginGeometryTimer = nullptr;
     }
   }
 
   nsCOMPtr<nsITimer> mNotifyDidPaintTimer;
   nsCOMPtr<nsITimer> mUpdatePluginGeometryTimer;
-  nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
+  nsTHashtable<nsRefPtrHashKey<nsIContent> > mRegisteredPlugins;
   // if mNeedsToUpdatePluginGeometry is set, then this is the frame to
   // use as the root of the subtree to search for plugin updates, or
   // null to use the root frame of this prescontext
   nsTArray<nsCOMPtr<nsIRunnable> > mWillPaintObservers;
   nsRevocableEventPtr<RunWillPaintObservers> mWillPaintFallbackEvent;
   nsIFrame* mUpdatePluginGeometryForFrame;
   PRUint32 mDOMGeneration;
   bool mNeedsToUpdatePluginGeometry;
--- a/layout/generic/ScrollbarActivity.cpp
+++ b/layout/generic/ScrollbarActivity.cpp
@@ -67,22 +67,22 @@ ScrollbarActivity::StartActivityFinished
                                             nsITimer::TYPE_ONE_SHOT);
 }
 
 void
 ScrollbarActivity::CancelActivityFinishedTimer()
 {
   if (mActivityFinishedTimer) {
     mActivityFinishedTimer->Cancel();
-    mActivityFinishedTimer = nsnull;
+    mActivityFinishedTimer = nullptr;
   }
 }
 
 nsIContent*
 ScrollbarActivity::GetScrollbarContent(bool aVertical)
 {
   nsIFrame* box = mScrollableFrame->GetScrollbarBox(aVertical);
-  return box ? box->GetContent() : nsnull;
+  return box ? box->GetContent() : nullptr;
 
-  return nsnull;
+  return nullptr;
 }
 
 } // namespace mozilla
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -758,17 +758,17 @@ nsColumnSetFrame::ReflowChildren(nsHTMLR
           aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
           kidNextInFlow->AddStateBits(NS_FRAME_IS_DIRTY);
           // Move any of our leftover columns to our overflow list. Our
           // next-in-flow will eventually pick them up.
           const nsFrameList& continuationColumns = mFrames.RemoveFramesAfter(child);
           if (continuationColumns.NotEmpty()) {
             SetOverflowFrames(PresContext(), continuationColumns);
           }
-          child = nsnull;
+          child = nullptr;
           break;
         } else if (contentBottom > aReflowState.mComputedMaxHeight ||
                    contentBottom > aReflowState.ComputedHeight()) {
           aColData.mShouldRevertToAuto = true;
         } else {
           // The number of columns required is too high.
           allFit = false;
         }
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4655,21 +4655,16 @@ nsIFrame::InvalidateInternalAfterResize(
     // the rect will already have been transformed into the root preserve-3d
     // frame coordinate space, and we should continue passing it up without
     // further transforms.
     aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED;
   }
 
   if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
       !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
-    // XXX for now I'm going to assume this is in the local coordinate space
-    // This only matters for frames with transforms and retained layers,
-    // which can't happen right now since transforms trigger fallback
-    // rendering and the display items that trigger layers are nested inside
-    // the nsDisplayTransform
     // XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of
     // invalidation, e.g. video update, 'opacity' change
     FrameLayerBuilder::InvalidateThebesLayerContents(this,
         aDamageRect + nsPoint(aX, aY));
     // Don't need to invalidate any more Thebes layers
     aFlags |= INVALIDATE_NO_THEBES_LAYERS;
     if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
       return;
@@ -5358,16 +5353,21 @@ nsFrame::GetDebugStateBits() const
 
 nsresult
 nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
 {
   aResult = aType;
   if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
     nsAutoString buf;
     mContent->Tag()->ToString(buf);
+    if (GetType() == nsGkAtoms::subDocumentFrame) {
+      nsAutoString src;
+      mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
+      buf.Append(NS_LITERAL_STRING(" src=") + src);
+    }
     aResult.Append(NS_LITERAL_STRING("(") + buf + NS_LITERAL_STRING(")"));
   }
   char buf[40];
   PR_snprintf(buf, sizeof(buf), "(%d)", ContentIndexInContainer(this));
   AppendASCIItoUTF16(buf, aResult);
   return NS_OK;
 }
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -477,28 +477,28 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
   if (!ShouldPropagateComputedHeightToScrolledContent()) {
     computedHeight = NS_UNCONSTRAINEDSIZE;
     computedMinHeight = 0;
     computedMaxHeight = NS_UNCONSTRAINEDSIZE;
   }
   if (aAssumeHScroll) {
     nsSize hScrollbarPrefSize;
     GetScrollbarMetrics(aState->mBoxState, mInner.mHScrollbarBox,
-                        nsnull, &hScrollbarPrefSize, false);
+                        nullptr, &hScrollbarPrefSize, false);
     if (computedHeight != NS_UNCONSTRAINEDSIZE)
       computedHeight = NS_MAX(0, computedHeight - hScrollbarPrefSize.height);
     computedMinHeight = NS_MAX(0, computedMinHeight - hScrollbarPrefSize.height);
     if (computedMaxHeight != NS_UNCONSTRAINEDSIZE)
       computedMaxHeight = NS_MAX(0, computedMaxHeight - hScrollbarPrefSize.height);
   }
 
   if (aAssumeVScroll) {
     nsSize vScrollbarPrefSize;
     GetScrollbarMetrics(aState->mBoxState, mInner.mVScrollbarBox,
-                        &vScrollbarPrefSize, nsnull, true);
+                        nullptr, &vScrollbarPrefSize, true);
     availWidth = NS_MAX(0, availWidth - vScrollbarPrefSize.width);
   }
 
   nsPresContext* presContext = PresContext();
 
   // Pass false for aInit so we can pass in the correct padding.
   nsHTMLReflowState kidReflowState(presContext, aState->mReflowState,
                                    mInner.mScrolledFrame,
@@ -2912,17 +2912,17 @@ nsGfxScrollFrameInner::AppendAnonymousCo
   aElements.MaybeAppendElement(mScrollCornerContent);
   aElements.MaybeAppendElement(mResizerContent);
 }
 
 void
 nsGfxScrollFrameInner::Destroy()
 {
   if (mScrollbarActivity) {
-    mScrollbarActivity = nsnull;
+    mScrollbarActivity = nullptr;
   }
 
   // Unbind any content created in CreateAnonymousContent from the tree
   nsContentUtils::DestroyAnonymousContent(&mHScrollbarContent);
   nsContentUtils::DestroyAnonymousContent(&mVScrollbarContent);
   nsContentUtils::DestroyAnonymousContent(&mScrollCornerContent);
   nsContentUtils::DestroyAnonymousContent(&mResizerContent);
 
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -426,17 +426,17 @@ nsObjectFrame::PrepForDrawing(nsIWidget 
     // On Mac, we need to invalidate ourselves since even windowed
     // plugins are painted through Thebes and we need to ensure
     // the Thebes layer containing the plugin is updated.
     if (parentWidget == GetNearestWidget()) {
       Invalidate(GetContentRectRelativeToSelf());
     }
 #endif
 
-    rpc->RegisterPluginForGeometryUpdates(this);
+    rpc->RegisterPluginForGeometryUpdates(mContent);
     rpc->RequestUpdatePluginGeometry(this);
 
     // Here we set the background color for this widget because some plugins will use 
     // the child window background color when painting. If it's not set, it may default to gray
     // Sometimes, a frame doesn't have a background color or is transparent. In this
     // case, walk up the frame tree until we do find a frame with a background color
     for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
       nscolor bgcolor =
@@ -446,17 +446,17 @@ nsObjectFrame::PrepForDrawing(nsIWidget 
         break;
       }
     }
   } else {
     // Changing to windowless mode changes the NPWindow geometry.
     FixupWindow(GetContentRectRelativeToSelf().Size());
 
 #ifndef XP_MACOSX
-    rpc->RegisterPluginForGeometryUpdates(this);
+    rpc->RegisterPluginForGeometryUpdates(mContent);
     rpc->RequestUpdatePluginGeometry(this);
 #endif
   }
 
   if (!IsHidden()) {
     viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
   }
 
@@ -734,42 +734,36 @@ nsObjectFrame::CallSetWindow(bool aCheck
 
   return rv;
 }
 
 void
 nsObjectFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
 {
   mInstanceOwner = aOwner;
-  if (!mInstanceOwner) {
-    nsRootPresContext* rpc = PresContext()->GetRootPresContext();
-    if (rpc) {
-      if (mWidget) {
-        if (mInnerView) {
-          mInnerView->DetachWidgetEventHandler(mWidget);
+  if (mInstanceOwner) {
+    return;
+  }
+  nsRootPresContext* rpc = PresContext()->GetRootPresContext();
+  if (rpc) {
+    rpc->UnregisterPluginForGeometryUpdates(mContent);
+  }
+  if (mWidget && mInnerView) {
+    mInnerView->DetachWidgetEventHandler(mWidget);
+    // Make sure the plugin is hidden in case an update of plugin geometry
+    // hasn't happened since this plugin became hidden.
+    nsIWidget* parent = mWidget->GetParent();
+    if (parent) {
+      nsTArray<nsIWidget::Configuration> configurations;
+      this->GetEmptyClipConfiguration(&configurations);
+      parent->ConfigureChildren(configurations);
 
-          rpc->UnregisterPluginForGeometryUpdates(this);
-          // Make sure the plugin is hidden in case an update of plugin geometry
-          // hasn't happened since this plugin became hidden.
-          nsIWidget* parent = mWidget->GetParent();
-          if (parent) {
-            nsTArray<nsIWidget::Configuration> configurations;
-            this->GetEmptyClipConfiguration(&configurations);
-            parent->ConfigureChildren(configurations);
-
-            mWidget->Show(false);
-            mWidget->Enable(false);
-            mWidget->SetParent(nullptr);
-          }
-        }
-      } else {
-#ifndef XP_MACOSX
-        rpc->UnregisterPluginForGeometryUpdates(this);
-#endif
-      }
+      mWidget->Show(false);
+      mWidget->Enable(false);
+      mWidget->SetParent(nullptr);
     }
   }
 }
 
 bool
 nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, bool aWithMouse)
 {
   if (aTabIndex)
@@ -2214,17 +2208,17 @@ nsObjectFrame::BeginSwapDocShells(nsICon
   if (!obj)
     return;
 
   nsObjectFrame* objectFrame = static_cast<nsObjectFrame*>(obj);
   NS_ASSERTION(!objectFrame->mWidget || objectFrame->mWidget->GetParent(),
                "Plugin windows must not be toplevel");
   nsRootPresContext* rootPC = objectFrame->PresContext()->GetRootPresContext();
   NS_ASSERTION(rootPC, "unable to unregister the plugin frame");
-  rootPC->UnregisterPluginForGeometryUpdates(objectFrame);
+  rootPC->UnregisterPluginForGeometryUpdates(aContent);
 }
 
 /*static*/ void
 nsObjectFrame::EndSwapDocShells(nsIContent* aContent, void*)
 {
   NS_PRECONDITION(aContent, "");
 
   // This function is called from a document content enumerator so we need
@@ -2240,17 +2234,17 @@ nsObjectFrame::EndSwapDocShells(nsIConte
   if (widget) {
     // Reparent the widget.
     nsIWidget* parent =
       rootPC->PresShell()->GetRootFrame()->GetNearestWidget();
     widget->SetParent(parent);
     objectFrame->CallSetWindow();
 
     // Register for geometry updates and make a request.
-    rootPC->RegisterPluginForGeometryUpdates(objectFrame);
+    rootPC->RegisterPluginForGeometryUpdates(aContent);
     rootPC->RequestUpdatePluginGeometry(objectFrame);
   }
 }
 
 nsIFrame*
 NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsObjectFrame(aContext);
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -112,16 +112,22 @@ public:
       static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
     }
     return NS_OK;
   }
 private:
   nsWeakFrame mFrame;
 };
 
+static void
+InsertViewsInReverseOrder(nsIView* aSibling, nsIView* aParent);
+
+static void
+EndSwapDocShellsForViews(nsIView* aView);
+
 NS_IMETHODIMP
 nsSubDocumentFrame::Init(nsIContent*     aContent,
                          nsIFrame*       aParent,
                          nsIFrame*       aPrevInFlow)
 {
   // determine if we are a <frame> or <iframe>
   if (aContent) {
     nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
@@ -141,16 +147,38 @@ nsSubDocumentFrame::Init(nsIContent*    
   // really need it or not, and the inner view will get it as the
   // parent.
   if (!HasView()) {
     rv = nsContainerFrame::CreateViewForFrame(this, true);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   EnsureInnerView();
 
+  // If we have a detached subdoc's root view on our frame loader, re-insert
+  // it into the view tree. This happens when we've been reframed, and
+  // ensures the presentation persists across reframes. If the frame element
+  // has changed documents however, we blow away the presentation.
+  nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
+  if (frameloader) {
+    nsCOMPtr<nsIDocument> oldContainerDoc;
+    nsIView* detachedViews =
+      frameloader->GetDetachedSubdocView(getter_AddRefs(oldContainerDoc));
+    if (detachedViews) {
+      if (oldContainerDoc == aContent->OwnerDoc()) {
+        // Restore stashed presentation.
+        ::InsertViewsInReverseOrder(detachedViews, mInnerView);
+        ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
+      } else {
+        // Presentation is for a different document, don't restore it.
+        frameloader->Hide();
+      }
+    }
+    frameloader->SetDetachedSubdocView(nullptr, nullptr);
+  }
+
   // Set the primary frame now so that
   // DocumentViewerImpl::FindContainerView called by ShowViewer below
   // can find it if necessary.
   aContent->SetPrimaryFrame(this);
 
   nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
   return NS_OK;
 }
@@ -753,36 +781,87 @@ nsSubDocumentFrame::AttributeChanged(PRI
 nsIFrame*
 NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsSubDocumentFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
 
+class nsHideViewer : public nsRunnable {
+public:
+  nsHideViewer(nsIContent* aFrameElement,
+               nsFrameLoader* aFrameLoader,
+               nsIPresShell* aPresShell,
+               bool aHideViewerIfFrameless)
+    : mFrameElement(aFrameElement),
+      mFrameLoader(aFrameLoader),
+      mPresShell(aPresShell),
+      mHideViewerIfFrameless(aHideViewerIfFrameless)
+  {
+    NS_ASSERTION(mFrameElement, "Must have a frame element");
+    NS_ASSERTION(mFrameLoader, "Must have a frame loader");
+    NS_ASSERTION(mPresShell, "Must have a presshell");
+  }
+
+  NS_IMETHOD Run()
+  {
+    // Flush frames, to ensure any pending display:none changes are made.
+    // Note it can be unsafe to flush if we've destroyed the presentation
+    // for some other reason, like if we're shutting down.
+    if (!mPresShell->IsDestroying()) {
+      mPresShell->FlushPendingNotifications(Flush_Frames);
+    }
+    nsIFrame* frame = mFrameElement->GetPrimaryFrame();
+    if (!frame && mHideViewerIfFrameless) {
+      // The frame element has no nsIFrame. Hide the nsFrameLoader,
+      // which destroys the presentation.
+      mFrameLoader->SetDetachedSubdocView(nullptr, nullptr);
+      mFrameLoader->Hide();
+   }
+    return NS_OK;
+  }
+private:
+  nsCOMPtr<nsIContent> mFrameElement;
+  nsRefPtr<nsFrameLoader> mFrameLoader;
+  nsCOMPtr<nsIPresShell> mPresShell;
+  bool mHideViewerIfFrameless;
+};
+
+static nsIView*
+BeginSwapDocShellsForViews(nsIView* aSibling);
+
 void
 nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   if (mPostedReflowCallback) {
     PresContext()->PresShell()->CancelReflowCallback(this);
     mPostedReflowCallback = false;
   }
-  
-  HideViewer();
+
+  // Detach the subdocument's views and stash them in the frame loader.
+  // We can then reattach them if we're being reframed (for example if
+  // the frame has been made position:fixed).
+  nsFrameLoader* frameloader = FrameLoader();
+  if (frameloader) {
+    nsIView* detachedViews = ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
+    frameloader->SetDetachedSubdocView(detachedViews, mContent->OwnerDoc());
+
+    // We call nsFrameLoader::HideViewer() in a script runner so that we can
+    // safely determine whether the frame is being reframed or destroyed.
+    nsContentUtils::AddScriptRunner(
+      new nsHideViewer(mContent,
+                       mFrameLoader,
+                       PresContext()->PresShell(),
+                       (mDidCreateDoc || mCallingShow)));
+  }
 
   nsLeafFrame::DestroyFrom(aDestructRoot);
 }
 
-void
-nsSubDocumentFrame::HideViewer()
-{
-  if (mFrameLoader && (mDidCreateDoc || mCallingShow))
-    mFrameLoader->Hide();
-}
-
 nsIntSize
 nsSubDocumentFrame::GetMarginAttributes()
 {
   nsIntSize result(-1, -1);
   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
   if (content) {
     const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
     if (attr && attr->Type() == nsAttrValue::eInteger)
--- a/layout/generic/nsSubDocumentFrame.h
+++ b/layout/generic/nsSubDocumentFrame.h
@@ -114,18 +114,19 @@ protected:
 
   bool IsInline() { return mIsInline; }
 
   virtual nscoord GetIntrinsicWidth();
   virtual nscoord GetIntrinsicHeight();
 
   virtual int GetSkipSides() const;
 
-  // Hide or show our document viewer
-  void HideViewer();
+  // Show our document viewer. The document viewer is hidden via a script
+  // runner, so that we can save and restore the presentation if we're
+  // being reframed.
   void ShowViewer();
 
   /* Obtains the frame we should use for intrinsic size information if we are
    * an HTML <object>, <embed> or <applet> (a replaced element - not <iframe>)
    * and our sub-document has an intrinsic size. The frame returned is the
    * frame for the document element of the document we're embedding.
    *
    * Called "Obtain*" and not "Get*" because of comment on GetDocShell that
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -1469,29 +1469,29 @@ HasTerminalNewline(const nsTextFrame* aF
 {
   if (aFrame->GetContentLength() == 0)
     return false;
   const nsTextFragment* frag = aFrame->GetContent()->GetText();
   return frag->CharAt(aFrame->GetContentEnd() - 1) == '\n';
 }
 
 static nscoord
-LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nsnull)
+LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nullptr)
 {
   if (aFrame->IsSVGText()) {
     return 0;
   }
   if (!aStyleText) {
     aStyleText = aFrame->GetStyleText();
   }
   return StyleToCoord(aStyleText->mLetterSpacing);
 }
 
 static nscoord
-WordSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nsnull)
+WordSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nullptr)
 {
   if (aFrame->IsSVGText()) {
     return 0;
   }
   if (!aStyleText) {
     aStyleText = aFrame->GetStyleText();
   }
   return aStyleText->mWordSpacing;
--- a/layout/generic/test/Makefile.in
+++ b/layout/generic/test/Makefile.in
@@ -9,16 +9,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 # in the list below, we make sure that the tests that require focus
 # run before test_plugin_clipping, which can steal focus for its window.
 MOCHITEST_FILES = \
+  test_contained_plugin_transplant.html \
   bug344830_testembed.svg \
   plugin_clipping_helper.xhtml \
   plugin_clipping_helper2.xhtml \
   plugin_clipping_helper_transformed.xhtml \
   plugin_clipping_helper_table.xhtml \
   plugin_clipping_lib.js \
   plugin_focus_helper.html \
   test_bug240933.html \
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/test_contained_plugin_transplant.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=775965
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 775965</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="run();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=775965">Mozilla Bug 775965</a>
+<p id="display"></p>
+<div id="content">
+
+<iframe id="iframe1" src="data:text/html,<embed type='application/x-test' width='200' height='200'></embed>"></iframe>
+<iframe id="iframe2"></iframe>
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 775965 **/
+SimpleTest.waitForExplicitFinish();
+
+function run() {
+  var iframe1 = document.getElementById("iframe1");
+  var iframe2 = document.getElementById("iframe2");
+  iframe1.parentNode.removeChild(iframe1);
+  iframe1.style.position = "fixed";
+  iframe2.contentDocument.body.appendChild(iframe1);
+  setTimeout(function() { ok(true, "We didn't crash!"); SimpleTest.finish(); }, 0);
+}
+
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/779003-1-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+   <style type="text/css">
+#searchPaginationFooter {
+  direction: rtl;
+}
+
+.backLink {
+  display: inline-block;
+}
+
+.nextLink {
+  display: inline-block;
+}
+
+.pagination,
+.pagination li {
+  display: inline-block;
+  margin: 0;
+}
+
+p { margin: 0; } 
+   </style>
+ </head>
+ <body>
+   <div>
+     <div id="searchPaginationFooter">
+       <p class="backLink"> &lt; <span class="gray">السابق</span></p>
+       <ul class="pagination">
+	 <li><span class="select">1</span></li>
+	 <li><a href="#page=2">2</a></li>
+	 <li><a href="#page=3">3</a></li>
+	 <li><a href="#page=4">4</a></li>
+	 <li><a href="#page=5">5</a></li>
+	 <li><a href="#page=6">6</a></li>
+	 <li><a href="#page=7">7</a></li>
+	 <li><a href="#page=8">8</a></li>
+	 <li>...</li>
+	 <li><a href="#page=325">325</a></li>
+       </ul>
+       <p class="nextLink"><a href="#page=2">التالي</a> &gt; </p>
+     </div>
+   </div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/779003-1.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+   <style type="text/css">
+#searchPaginationFooter {
+  direction: rtl;
+}
+
+.backLink {
+  display: inline;
+}
+
+.nextLink {
+  display: inline;
+}
+
+.pagination,
+.pagination li {
+  display: inline;
+}
+   </style>
+ </head>
+ <body>
+   <div>
+     <div id="searchPaginationFooter">
+       <p class="backLink"> &lt; <span class="gray">السابق</span></p>
+       <ul class="pagination">
+	 <li><span class="select">1</span></li>
+	 <li><a href="#page=2">2</a></li>
+	 <li><a href="#page=3">3</a></li>
+	 <li><a href="#page=4">4</a></li>
+	 <li><a href="#page=5">5</a></li>
+	 <li><a href="#page=6">6</a></li>
+	 <li><a href="#page=7">7</a></li>
+	 <li><a href="#page=8">8</a></li>
+	 <li>...</li>
+	 <li><a href="#page=325">325</a></li>
+       </ul>
+       <p class="nextLink"><a href="#page=2">التالي</a> &gt; </p>
+     </div>
+   </div>
+ </body>
+</html>
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -118,8 +118,9 @@ fails-if(/^Windows\x20NT\x206\.1/.test(h
 == 726420-1.html 726420-1-ref.html
 == 726460-1.html 726460-1-ref.html
 == 729047-1.html 729047-1-ref.html
 == 730562-1.html 730562-1-ref.html
 == 746987-1.html 746987-1-ref.html
 == 746987-2.html 746987-2-ref.html
 == 746987-3.html 746987-3-ref.html
 == 746987-4.html 746987-4-ref.html
+== 779003-1.html 779003-1-ref.html
--- a/layout/reftests/w3c-css/README
+++ b/layout/reftests/w3c-css/README
@@ -1,16 +1,17 @@
 W3C CSS Test Suite Directory
 ----------------------------
 
 This directory is for tests that are sync'ed with the official
 W3C CSS test suites at http://test.csswg.org/.
  
 submitted/ is for tests that are to be submitted to W3C.
-This directory is sync'ed automatically with the contributors/mozilla/
+This directory is sync'ed automatically with the
+contributors/mozilla/submitted/mozilla-central-reftests/
 directory in the CSSWG repository. The master copy is Mozilla's.
 
 received/ is for tests that are received from W3C.
 This directory is sync'ed semi-automatically with the approved/
 directory in the CSSWG repository. The master copy is CSSWG's.
 Don't make changes here; they'll be overwritten by the next sync.
 
 Legal Stuff
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -534,16 +534,17 @@ pref("services.sync.prefs.sync.signon.re
 
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with nsEventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 pref("layers.acceleration.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", true);
+pref("layers.async-video.enabled", true);
 
 pref("notification.feature.enabled", true);
 
 // prevent tooltips from showing up
 pref("browser.chrome.toolbar_tips", false);
 pref("indexedDB.feature.enabled", true);
 pref("dom.indexedDB.warningQuota", 5);
 
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -626,27 +626,24 @@ abstract public class GeckoApp
         if (shouldUpdateThumbnail(tab)) {
             Bitmap b = tab.getThumbnailBitmap();
             b.copyPixelsFromBuffer(data);
             processThumbnail(tab, b, null);
         }
     }
 
     void processThumbnail(Tab thumbnailTab, Bitmap bitmap, byte[] compressed) {
-        if (shouldUpdateThumbnail(thumbnailTab)) {
-            if (compressed == null) {
-                ByteArrayOutputStream bos = new ByteArrayOutputStream();
-                bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
-                compressed = bos.toByteArray();
+        try {
+            if (bitmap == null) {
+                if (compressed == null) {
+                    Log.e(LOGTAG, "processThumbnail: one of bitmap or compressed must be non-null!");
+                    return;
+                }
+                bitmap = BitmapFactory.decodeByteArray(compressed, 0, compressed.length);
             }
-        }
-
-        try {
-            if (bitmap == null)
-                bitmap = BitmapFactory.decodeByteArray(compressed, 0, compressed.length);
             thumbnailTab.updateThumbnail(bitmap);
         } catch (OutOfMemoryError ome) {
             Log.w(LOGTAG, "decoding byte array ran out of memory", ome);
         }
     }
 
     private boolean shouldUpdateThumbnail(Tab tab) {
         return (Tabs.getInstance().isSelectedTab(tab) || areTabsShown());
--- a/mobile/android/base/PropertyAnimator.java
+++ b/mobile/android/base/PropertyAnimator.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
 /* 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/. */
 
 package org.mozilla.gecko;
 
+import android.os.Handler;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -136,28 +137,30 @@ public class PropertyAnimator extends Ti
 
         if (mListener != null) {
             mListener.onPropertyAnimationEnd();
             mListener = null;
         }
     }
 
     private void invalidate(final ElementHolder element, final int delta) {
-        View v = (element == null ? null : element.view);
-        if (v == null)
+        final View view = element.view;
+
+        Handler handler = view.getHandler();
+        if (handler == null)
             return;
 
         // Post the layout changes on the view's UI thread.
-        v.getHandler().post(new Runnable() {
+        handler.post(new Runnable() {
             @Override
             public void run() {
-                // Check if the element and view still exist
-                View view = (element == null ? null : element.view);
-                if (view == null)
-                     return;
+                // check to see if the view was detached between the check above and this code
+                // getting run on the UI thread.
+                if (view.getHandler() == null)
+                    return;
             
                 if (element.property == Property.SLIDE_TOP) {
                     view.scrollTo(view.getScrollX(), delta);
                     return;
                 } else if (element.property == Property.SLIDE_LEFT) {
                     view.scrollTo(delta, view.getScrollY());
                     return;
                 }
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -170,21 +170,23 @@ public final class Tab {
     }
 
     synchronized void freeBuffer() {
         DirectBufferAllocator.free(mThumbnailBuffer);
         mThumbnailBuffer = null;
     }
 
     int getThumbnailWidth() {
-        return (int) (GeckoApp.mAppContext.getResources().getDimension(R.dimen.tab_thumbnail_width));
+        int desiredWidth = (int) (GeckoApp.mAppContext.getResources().getDimension(R.dimen.tab_thumbnail_width));
+        return desiredWidth & ~0x1;
     }
 
     int getThumbnailHeight() {
-        return (int) (GeckoApp.mAppContext.getResources().getDimension(R.dimen.tab_thumbnail_height));
+        int desiredHeight = (int) (GeckoApp.mAppContext.getResources().getDimension(R.dimen.tab_thumbnail_height));
+        return desiredHeight & ~0x1;
     }
 
     public void updateThumbnail(final Bitmap b) {
         final Tab tab = this;
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
                 if (b != null) {
                     try {
--- a/mobile/android/base/tests/testHistoryTab.java.in
+++ b/mobile/android/base/tests/testHistoryTab.java.in
@@ -1,14 +1,15 @@
 #filter substitution
 package @ANDROID_PACKAGE_NAME@.tests;
 
 import @ANDROID_PACKAGE_NAME@.*;
 
 import android.app.Activity;
+import android.view.ViewGroup;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.ExpandableListView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.ImageView;
 import android.widget.TabHost;
 import android.text.TextUtils;
@@ -123,21 +124,35 @@ public class testHistoryTab extends Base
         // clear VKB
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
         mSolo.waitForText(url);
 
         View child = list.getChildAt(0);
         mSolo.clickLongOnView(child);
         mAsserter.is(false, mSolo.waitForText("Open in New Tab"), "Header rows should not show a context menu");
 
+        // wait for the history list to be populated
         waitForTest(new BooleanTest() {
             public boolean test() {
                 if (list.getChildAt(1) == null) {
                     return false;
                 }
+                View firstChild = list.getChildAt(1);
+                if (firstChild instanceof android.view.ViewGroup) {
+                    ViewGroup group = (ViewGroup)firstChild;
+                    if (group.getChildCount() < 1) {
+                        return false;
+                    }
+                    for (int i = 0; i < group.getChildCount(); i++) {
+                        View grandChild = group.getChildAt(i);
+                        if (grandChild instanceof android.widget.TextView) {
+                            mAsserter.ok(true, "found TextView:", ((android.widget.TextView)grandChild).getText().toString());
+                        }
+                    }
+                }
                 return true;
             }
         }, WAIT_FOR_CHILD_TIMEOUT);
         child = list.getChildAt(1);
 
         mSolo.clickLongOnView(child);
 
         // TODO: Test clicking these does the right thing
--- a/mobile/android/themes/core/content.css
+++ b/mobile/android/themes/core/content.css
@@ -311,19 +311,11 @@ textarea:active {
  * Generate an additional space after the anonymous div to make it easier to
  * to position the caret at the end of the text
  */
 input > .anonymous-div:after {
   content: "";
   margin: 16px;
 }
 
-/*
- * Enforce nearest scaling for video in order not to lose too much performance
- * after fixing bug 598736 ("Use higher-quality imageinterpolation on mobile")
- */
-video {
-    image-rendering: -moz-crisp-edges;
-}
-
 xul|menulist {
   -moz-binding: url("chrome://browser/content/bindings/menulist.xml#menulist");
 }
--- a/testing/marionette/client/marionette/runtests.py
+++ b/testing/marionette/client/marionette/runtests.py
@@ -22,20 +22,20 @@ try:
     from mozhttpd import iface, MozHttpd
 except ImportError:
     print "manifestparser or mozhttpd not found!  Please install mozbase:\n"
     print "\tgit clone git://github.com/mozilla/mozbase.git"
     print "\tpython setup_development.py\n"
     import sys
     sys.exit(1)
 
-
 from marionette import Marionette
 from marionette_test import MarionetteJSTestCase
 
+
 class MarionetteTestResult(unittest._TextTestResult):
 
     def __init__(self, *args):
         super(MarionetteTestResult, self).__init__(*args)
         self.passed = 0
         self.perfdata = None
         self.tests_passed = []
 
@@ -84,18 +84,20 @@ class MarionetteTextTestRunner(unittest.
     resultclass = MarionetteTestResult
 
     def _makeResult(self):
         return self.resultclass(self.stream, self.descriptions, self.verbosity)
 
     def run(self, test):
         "Run the given test case or test suite."
         result = self._makeResult()
-        result.failfast = self.failfast
-        result.buffer = self.buffer
+        if hasattr(self, 'failfast'):
+            result.failfast = self.failfast
+        if hasattr(self, 'buffer'):
+            result.buffer = self.buffer
         startTime = time.time()
         startTestRun = getattr(result, 'startTestRun', None)
         if startTestRun is not None:
             startTestRun()
         try:
             test(result)
         finally:
             stopTestRun = getattr(result, 'stopTestRun', None)
@@ -465,42 +467,51 @@ class MarionetteTestRunner(object):
 
         assembly = doc.createElement('assembly')
         assembly.setAttribute('name', 'Tests')
         assembly.setAttribute('time', str(self.elapsedtime))
         assembly.setAttribute('total', str(sum([results.testsRun for
                                                     results in results_list])))
         assembly.setAttribute('passed', str(sum([results.passed for
                                                      results in results_list])))
-        assembly.setAttribute('failed', str(sum([len(results.failures) +
-                                                 len(results.errors) +
-                                                 len(results.unexpectedSuccesses)
+
+        def failed_count(results):
+            count = len(results.failures) + len(results.errors)
+            if hasattr(results, 'unexpectedSuccesses'):
+                count += len(results.unexpectedSuccesses)
+            return count
+
+        assembly.setAttribute('failed', str(sum([failed_count(results)
                                                  for results in results_list])))
-        assembly.setAttribute('skipped', str(sum([len(results.skipped) +
-                                                  len(results.expectedFailures)
-                                                  for results in results_list])))
+        if hasattr(results, 'skipped'):
+            assembly.setAttribute('skipped', str(sum([len(results.skipped) +
+                                                      len(results.expectedFailures)
+                                                      for results in results_list])))
 
         for results in results_list:
             classes = {} # str -> xml class element
 
             for tup in results.errors:
                 _extract_xml(*tup, result='Fail')
 
             for tup in results.failures:
                 _extract_xml(*tup, result='Fail')
 
-            for test in results.unexpectedSuccesses:
-                # unexpectedSuccesses is a list of Testcases only, no tuples
-                _extract_xml(test, text='TEST-UNEXPECTED-PASS', result='Fail')
+            if hasattr(results, 'unexpectedSuccesses'):
+                for test in results.unexpectedSuccesses:
+                    # unexpectedSuccesses is a list of Testcases only, no tuples
+                    _extract_xml(test, text='TEST-UNEXPECTED-PASS', result='Fail')
 
-            for tup in results.skipped:
-                _extract_xml(*tup, result='Skip')
+            if hasattr(results, 'skipped'):
+                for tup in results.skipped:
+                    _extract_xml(*tup, result='Skip')
 
-            for tup in results.expectedFailures:
-                _extract_xml(*tup, result='Skip')
+            if hasattr(results, 'expectedFailures'):
+                for tup in results.expectedFailures:
+                    _extract_xml(*tup, result='Skip')
 
             for test in results.tests_passed:
                 _extract_xml(test)
 
             for cls in classes.itervalues():
                 assembly.appendChild(cls)
 
         doc.appendChild(assembly)
--- a/testing/mochitest/android.json
+++ b/testing/mochitest/android.json
@@ -121,31 +121,24 @@
  "docshell/test/test_bug344861.html": "",
  "docshell/test/test_bug94514.html": "TIMED_OUT",
  "docshell/test/test_bug413310.html": "",
  "docshell/test/test_bug598895.html": "",
  "docshell/test/test_bug637644.html": "",
  "docshell/test/test_bug668513.html": "RANDOM",
  "dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html": "TIMED_OUT, bug 766586",
  "dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html": "TIMED_OUT, bug 766586",
- "dom/devicestorage/test/test_stat.html": "bug 781789",
+ "dom/devicestorage": "bug 781789 & bug 782275",
  "dom/imptests/editing/conformancetest/test_event.html": "",
  "dom/imptests/editing/conformancetest/test_runtest.html": "",
- "dom/imptests/editing/selecttest/test_addRange.html": "bug 775227", 
+ "dom/imptests/editing/selecttest": "bug 782431 & bug 775227", 
  "dom/imptests/html/tests/submission/Mozilla/test_window-onerror-parse-error.html": "",
  "dom/imptests/html/tests/submission/Mozilla/test_window-onerror-runtime-error-throw.html": "",
  "dom/imptests/html/tests/submission/Mozilla/test_window-onerror-runtime-error.html": "",
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-cloneContents.html": "bug 775227", 
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-compareBoundaryPoints.html": "bug 775227",
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-deleteContents.html": "bug 775227",
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-extractContents.html": "bug 775227",
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-insertNode.html": "bug 775227",
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html": "bug 775227",
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-set.html": "bug 775227",
- "dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html": "bug 775227",
+ "dom/imptests/webapps/DOMCore/tests/approved": "bug 782328", 
  "dom/imptests/webapps/DOMCore/tests/submissions": "bug 782254",
  "dom/imptests/webapps/WebStorage/tests/submissions": "bug 781837 & bug 775227",
  "dom/indexedDB/test/test_third_party.html": "TIMED_OUT",
  "dom/indexedDB/test/test_event_propagation.html": "TIMED_OUT, bug 780855",
  "dom/network/tests/test_network_basics.html": "",
  "dom/settings/tests/test_settings_events.html": "",
  "dom/settings/tests/test_settings_basics.html": "",
  "dom/contacts/tests/test_contacts_blobs.html": "",
@@ -169,25 +162,16 @@
  "dom/tests/mochitest/bugs/test_bug479143.html": "",
  "dom/tests/mochitest/bugs/test_bug504862.html": "RANDOM",
  "dom/tests/mochitest/bugs/test_bug597809.html": "",
  "dom/tests/mochitest/bugs/test_bug61098.html": "",
  "dom/tests/mochitest/bugs/test_bug641552.html": "",
  "dom/tests/mochitest/bugs/test_devicemotion_multiple_listeners.html": "bug 775227",
  "dom/tests/mochitest/bugs/test_resize_move_windows.html": "TIMED_OUT",
  "dom/tests/mochitest/bugs/test_window_bar.html": "",
- "dom/devicestorage/ipc/test_ipc.html": "",
- "dom/devicestorage/test/test_basic.html": "",
- "dom/devicestorage/test/test_dotdot.html": "",
- "dom/devicestorage/test/test_enumerate.html": "",
- "dom/devicestorage/test/test_enumerateMultipleContinue.html": "",
- "dom/devicestorage/test/test_enumerateOptions.html": "",
- "dom/devicestorage/test/test_lastModificationFilter.html": "",
- "dom/devicestorage/test/test_overwrite.html": "",
- "dom/devicestorage/test/test_sanity.html": "",
  "dom/tests/mochitest/dom-level2-core/test_documentimportnode03.html": "",
  "dom/tests/mochitest/dom-level2-core/test_documentimportnode04.html": "",
  "dom/tests/mochitest/dom-level2-core/test_documentimportnode21.html": "",
  "dom/tests/mochitest/general/test_497898.html": "",
  "dom/tests/mochitest/general/test_focusrings.xul": "TIMED_OUT",
  "dom/tests/mochitest/general/test_vibrator.html": "CRASH_SUTAGENT",
  "dom/tests/mochitest/general/test_windowProperties.html": "",
  "dom/tests/mochitest/geolocation/test_allowCurrent.html": "TIMED_OUT",
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -733,16 +733,19 @@ class XPCShellTests(object):
             changedEnv = (set("%s=%s" % i for i in self.env.iteritems())
                           - set("%s=%s" % i for i in os.environ.iteritems()))
             self.log.info("TEST-INFO | %s | environment: %s" % (name, list(changedEnv)))
         startTime = time.time()
 
         proc = self.launchProcess(completeCmd,
                     stdout=pStdout, stderr=pStderr, env=self.env, cwd=testdir)
 
+        if interactive:
+          self.log.info("TEST-INFO | %s | Process ID: %d" % (name, proc.pid))
+
         # Allow user to kill hung subprocess with SIGINT w/o killing this script
         # - don't move this line above launchProcess, or child will inherit the SIG_IGN
         signal.signal(signal.SIGINT, markGotSIGINT)
         # |stderr == None| as |pStderr| was either |None| or redirected to |stdout|.
         stdout, stderr = self.communicate(proc)
         signal.signal(signal.SIGINT, signal.SIG_DFL)
 
         if interactive:
--- a/toolkit/components/osfile/osfile_shared_allthreads.jsm
+++ b/toolkit/components/osfile/osfile_shared_allthreads.jsm
@@ -1,20 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 {
   if (typeof Components != "undefined") {
-    // We do not wish osfile_shared.jsm to be used directly as a main thread
-    // module yet. When time comes, it will be loaded by a combination of
-    // a main thread front-end/worker thread implementation that makes sure
-    // that we are not executing synchronous IO code in the main thread.
-
-    throw new Error("osfile_shared_allthreads.jsm cannot be used from the main thread yet");
+    var EXPORTED_SYMBOLS = ["OS"];
+    Components.utils.import("resource://gre/modules/ctypes.jsm");
+    Components.classes["@mozilla.org/net/osfileconstantsservice;1"].
+      getService(Components.interfaces.nsIOSFileConstantsService).init();
   }
 
   (function(exports) {
      "use strict";
      /*
       * This block defines |OS.Shared.Type|. However, |OS| can exist already
       * (in particular, if this code is executed in a worker thread, it is
       * defined).
@@ -82,16 +80,35 @@
          throw new TypeError("Type expects as second argument a ctypes.CType"+
                              ", got: " + implementation);
        }
        Object.defineProperty(this, "name", { value: name });
        Object.defineProperty(this, "implementation", { value: implementation });
      }
      Type.prototype = {
        /**
+        * Serialize a value of |this| |Type| into a format that can
+        * be transmitted as a message (not necessarily a string).
+        *
+        * In the default implementation, the method returns the
+        * value unchanged.
+        */
+       toMsg: function default_toMsg(value) {
+         return value;
+       },
+       /**
+        * Deserialize a message to a value of |this| |Type|.
+        *
+        * In the default implementation, the method returns the
+        * message unchanged.
+        */
+       fromMsg: function default_fromMsg(msg) {
+         return msg;
+       },
+       /**
         * Import a value from C.
         *
         * In this default implementation, return the value
         * unchanged.
         */
        importFromC: function default_importFromC(value) {
          return value;
        },
@@ -186,16 +203,66 @@
       * @param {string} name The name of this type.
       * @param {CType} implementation The type of this pointer.
       */
      function PtrType(name, implementation) {
        Type.call(this, name, implementation);
      }
      PtrType.prototype = Object.create(Type.prototype);
 
+     /**
+      * Convert a value to a pointer.
+      *
+      * Protocol:
+      * - |null| returns |null|
+      * - a string returns |{string: value}|
+      * - an ArrayBuffer returns |{ptr: address_of_buffer}|
+      * - a C array returns |{ptr: address_of_buffer}|
+      * everything else raises an error
+      */
+     PtrType.prototype.toMsg = function ptr_toMsg(value) {
+       if (value == null) {
+         return null;
+       }
+       if (typeof value == "string") {
+         return { string: value };
+       }
+       let normalized;
+       if ("byteLength" in value) { // ArrayBuffer
+         normalized = Types.uint8_t.in_ptr.implementation(value);
+       } else if ("addressOfElement" in value) { // C array
+         normalized = value.addressOfElement(0);
+       } else if ("isNull" in value) { // C pointer
+         normalized = value;
+       } else {
+         throw new TypeError("Value " + value +
+           " cannot be converted to a pointer");
+       }
+       let cast = Types.uintptr_t.cast(normalized);
+       return {ptr: cast.value.toString()};
+     };
+
+     /**
+      * Convert a message back to a pointer.
+      */
+     PtrType.prototype.fromMsg = function ptr_fromMsg(msg) {
+       if (msg == null) {
+         return null;
+       }
+       if ("string" in msg) {
+         return msg.string;
+       }
+       if ("ptr" in msg) {
+         let address = ctypes.uintptr_t(msg.ptr);
+         return this.cast(address);
+       }
+       throw new TypeError("Message " + msg.toSource() +
+         " does not represent a pointer");
+     };
+
      exports.OS.Shared.Type = Type;
      let Types = Type;
 
      /*
       * Some values are large integers on 64 bit platforms. Unfortunately,
       * in practice, 64 bit integers cannot be manipulated in JS. We
       * therefore project them to regular numbers whenever possible.
       */
@@ -752,16 +819,19 @@
      Strings.decodeAll = function decodeAll(encoding, source, bytes) {
        let decoded = _decodeAll(encoding, source, bytes);
        if (!decoded) {
          return null;
        }
        return Strings.importWString(decoded);
      };
 
+     exports.OS.Shared.Utils = { Strings: Strings };
+
+
      /**
       * Specific tools that don't really fit anywhere.
       */
      let _aux = {};
      exports.OS.Shared._aux = _aux;
 
      /**
       * Utility function shared by implementations of |OS.File.open|:
--- a/toolkit/components/osfile/osfile_unix_allthreads.jsm
+++ b/toolkit/components/osfile/osfile_unix_allthreads.jsm
@@ -118,9 +118,15 @@ if (typeof Components != "undefined") {
    */
   Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
     get: function becauseNoSuchFile() {
       return this.unixErrno == OS.Constants.libc.ENOENT;
     }
   });
 
   exports.OS.Shared.Unix.Error = OSError;
+
+  // Special constants that need to be defined on all platforms
+
+   Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.libc.SEEK_SET });
+   Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.libc.SEEK_CUR });
+   Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.libc.SEEK_END });
 })(this);
--- a/toolkit/components/osfile/osfile_unix_front.jsm
+++ b/toolkit/components/osfile/osfile_unix_front.jsm
@@ -136,31 +136,28 @@
        /**
         * Change the current position in the file.
         *
         * @param {number} pos The new position. Whether this position
         * is considered from the current position, from the start of
         * the file or from the end of the file is determined by
         * argument |whence|.  Note that |pos| may exceed the length of
         * the file.
-        * @param {number=} whence The reference position. If omitted or
-        * |OS.File.POS_START|, |pos| is taken from the start of the file.
-        * If |OS.File.POS_CURRENT|, |pos| is taken from the current position
-        * in the file. If |OS.File.POS_END|, |pos| is taken from the end of
-        * the file.
+        * @param {number=} whence The reference position. If omitted
+        * or |OS.File.POS_START|, |pos| is relative to the start of the
+        * file.  If |OS.File.POS_CURRENT|, |pos| is relative to the
+        * current position in the file. If |OS.File.POS_END|, |pos| is
+        * relative to the end of the file.
         *
         * @return The new position in the file.
         */
        setPosition: function setPosition(pos, whence) {
-         // We are cheating to avoid one unnecessary conversion:
-         // In this implementation,
-         // OS.File.POS_START == OS.Constants.libc.SEEK_SET
-         // OS.File.POS_CURRENT == OS.Constants.libc.SEEK_CUR
-         // OS.File.POS_END == OS.Constants.libc.SEEK_END
-         whence = (whence == undefined)?OS.Constants.libc.SEEK_SET:whence;
+         if (whence === undefined) {
+           whence = Const.SEEK_START;
+         }
          return throw_on_negative("setPosition",
            UnixFile.lseek(this.fd, pos, whence)
          );
        },
 
        /**
         * Fetch the information on the file.
         *
@@ -805,18 +802,17 @@
 
      function throw_on_null(operation, result) {
        if (result == null || (result.isNull && result.isNull())) {
          throw new File.Error(operation);
        }
        return result;
      }
 
-     File.POS_START = exports.OS.Constants.libc.SEEK_SET;
-     File.POS_CURRENT = exports.OS.Constants.libc.SEEK_CUR;
-     File.POS_END = exports.OS.Constants.libc.SEEK_END;
-
      File.Unix = exports.OS.Unix.File;
      File.Error = exports.OS.Shared.Unix.Error;
      exports.OS.File = File;
 
+     Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
+     Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
+     Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
    })(this);
 }
--- a/toolkit/components/osfile/osfile_win_allthreads.jsm
+++ b/toolkit/components/osfile/osfile_win_allthreads.jsm
@@ -128,9 +128,15 @@ if (typeof Components != "undefined") {
    */
   Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
     get: function becauseNoSuchFile() {
       return this.winLastError == exports.OS.Constants.Win.ERROR_FILE_NOT_FOUND;
     }
   });
 
   exports.OS.Shared.Win.Error = OSError;
-})(this);
\ No newline at end of file
+
+  // Special constants that need to be defined on all platforms
+
+  Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.Win.FILE_BEGIN });
+  Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.Win.FILE_CURRENT });
+  Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.Win.FILE_END });
+})(this);
--- a/toolkit/components/osfile/osfile_win_front.jsm
+++ b/toolkit/components/osfile/osfile_win_front.jsm
@@ -162,31 +162,28 @@
        /**
         * Change the current position in the file.
         *
         * @param {number} pos The new position. Whether this position
         * is considered from the current position, from the start of
         * the file or from the end of the file is determined by
         * argument |whence|.  Note that |pos| may exceed the length of
         * the file.
-        * @param {number=} whence The reference position. If omitted or
-        * |OS.File.POS_START|, |pos| is taken from the start of the file.
-        * If |OS.File.POS_CURRENT|, |pos| is taken from the current position
-        * in the file. If |OS.File.POS_END|, |pos| is taken from the end of
-        * the file.
+        * @param {number=} whence The reference position. If omitted
+        * or |OS.File.POS_START|, |pos| is relative to the start of the
+        * file.  If |OS.File.POS_CURRENT|, |pos| is relative to the
+        * current position in the file. If |OS.File.POS_END|, |pos| is
+        * relative to the end of the file.
         *
         * @return The new position in the file.
         */
        setPosition: function setPosition(pos, whence) {
-         // We are cheating to avoid one unnecessary conversion:
-         // In this implementation,
-         // OS.File.POS_START == OS.Constants.Win.FILE_BEGIN
-         // OS.File.POS_CURRENT == OS.Constants.Win.FILE_CURRENT
-         // OS.File.POS_END == OS.Constants.Win.FILE_END
-         whence = (whence == undefined)?Const.FILE_BEGIN:whence;
+         if (whence === undefined) {
+           whence = Const.FILE_BEGIN;
+         }
          return throw_on_negative("setPosition",
            WinFile.SetFilePointer(this.fd, pos, null, whence));
        },
 
        /**
         * Fetch the information on the file.
         *
         * @return File.Info The information on |this| file.
@@ -809,25 +806,19 @@
      }
      function throw_on_null(operation, result) {
        if (result == null || (result.isNull && result.isNull())) {
          throw new File.Error(operation);
        }
        return result;
      }
 
-
-
-
-     // Constants
-
-     // Constants for File.prototype.setPosition
-     File.POS_START = Const.FILE_BEGIN;
-     File.POS_CURRENT = Const.FILE_CURRENT;
-     File.POS_END = Const.FILE_END;
-
      File.Win = exports.OS.Win.File;
      File.Error = exports.OS.Shared.Win.Error;
      exports.OS.File = File;
 
      exports.OS.Path = exports.OS.Win.Path;
+
+     Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
+     Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
+     Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
    })(this);
 }
--- a/toolkit/components/osfile/osfileutils.cpp
+++ b/toolkit/components/osfile/osfileutils.cpp
@@ -90,105 +90,105 @@ MOZ_EXPORT_API(PRUnichar*) osfile_wstrdu
 
 MOZ_EXPORT_API(PRUnichar*) osfile_DecodeAll(
    const char* aEncoding,
    const char* aSource,
    const int32_t aBytesToDecode)
 {
   if (!aEncoding || !aSource) {
     error_invalid_argument();
-    return nsnull;
+    return nullptr;
   }
 
   nsresult rv;
   nsCOMPtr<nsICharsetConverterManager> manager =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     error_not_supported();
-    return nsnull;
+    return nullptr;
   }
 
   nsCOMPtr<nsIUnicodeDecoder> decoder;
   rv = manager->GetUnicodeDecoder(aEncoding, getter_AddRefs(decoder));
   if (NS_FAILED(rv)) {
     error_invalid_argument();
-    return nsnull;
+    return nullptr;
   }
 
   // Compute an upper bound to the number of chars, allocate buffer
 
   int32_t srcBytes = aBytesToDecode;
   int32_t upperBoundChars = 0;
   rv = decoder->GetMaxLength(aSource, srcBytes, &upperBoundChars);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   int32_t bufSize = (upperBoundChars + 1) * sizeof (PRUnichar);
 
   mozilla::ScopedFreePtr<PRUnichar> dest((PRUnichar*)NS_Alloc(bufSize));
-  if (dest.get() == nsnull) {
+  if (dest.get() == nullptr) {
     error_no_memory();
-    return nsnull;
+    return nullptr;
   }
 
   // Convert, add trailing \0
 
   rv = decoder->Convert(aSource, &srcBytes, dest.rwget(), &upperBoundChars);
   if (NS_FAILED(rv)) {
     error_invalid_argument();
-    return nsnull;
+    return nullptr;
   }
 
   dest.rwget()[upperBoundChars] = '\0';
 
   return dest.forget();
 }
 
 MOZ_EXPORT_API(char*) osfile_EncodeAll(
    const char* aEncoding,
    const PRUnichar* aSource,
    int32_t* aBytesProduced)
 {
   if (!aEncoding || !aSource || !aBytesProduced) {
     error_invalid_argument();
-    return nsnull;
+    return nullptr;
   }
 
   nsresult rv;
   nsCOMPtr<nsICharsetConverterManager> manager =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     error_not_supported();
-    return nsnull;
+    return nullptr;
   }
 
   nsCOMPtr<nsIUnicodeEncoder> encoder;
   rv = manager->GetUnicodeEncoder(aEncoding, getter_AddRefs(encoder));
   if (NS_FAILED(rv)) {
     error_invalid_argument();
-    return nsnull;
+    return nullptr;
   }
 
   int32_t srcChars = NS_strlen(aSource);
 
   int32_t upperBoundBytes = 0;
   rv = encoder->GetMaxLength(aSource, srcChars, &upperBoundBytes);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   printf_stderr("Encoding %d chars into at up to %d bytes\n", srcChars, upperBoundBytes);
   int32_t bufSize = upperBoundBytes;
   mozilla::ScopedFreePtr<char> dest((char*)NS_Alloc(bufSize));
 
-  if (dest.get() == nsnull) {
+  if (dest.get() == nullptr) {
     error_no_memory();
-    return nsnull;
+    return nullptr;
   }
 
   rv = encoder->Convert(aSource, &srcChars, dest.rwget(), &upperBoundBytes);
   if (NS_FAILED(rv)) {
     error_invalid_argument();
-    return nsnull;
+    return nullptr;
   }
 
   *aBytesProduced = upperBoundBytes;
   return dest.forget();
 }
 
 } // extern "C"
--- a/toolkit/components/osfile/tests/mochi/Makefile.in
+++ b/toolkit/components/osfile/tests/mochi/Makefile.in
@@ -13,11 +13,13 @@ include $(DEPTH)/config/autoconf.mk
 MODULE          = osfile
 
 MOCHITEST_CHROME_FILES := \
   test_osfile_back.xul \
   worker_test_osfile_unix.js \
   worker_test_osfile_win.js \
   test_osfile_front.xul \
   worker_test_osfile_front.js \
+  test_osfile_comms.xul \
+  worker_test_osfile_comms.js \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/toolkit/components/osfile/tests/mochi/test_osfile_comms.xul
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="Testing OS.File on a chrome worker thread"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="test();">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript">
+  <![CDATA[
+
+"use strict";
+
+let worker;
+
+let test = function test() {
+  SimpleTest.ok(true, "test_osfile_comms.xul: Starting test");
+  Components.utils.import("resource://gre/modules/ctypes.jsm");
+  Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
+  worker = new ChromeWorker("worker_test_osfile_comms.js");
+  SimpleTest.waitForExplicitFinish();
+  worker.onerror = function onerror(error) {
+    SimpleTest.ok(false, "received error "+error);
+  }
+  worker.onmessage = function onmessage(msg) {
+    Components.utils.forceShrinkingGC();
+    switch (msg.data.kind) {
+    case "is":
+      SimpleTest.ok(msg.data.outcome, msg.data.description +
+         " ("+ msg.data.a + " ==? " + msg.data.b + ")" );
+      return;
+    case "isnot":
+      SimpleTest.ok(msg.data.outcome, msg.data.description +
+      " ("+ msg.data.a + " !=? " + msg.data.b + ")" );
+         return;
+    case "ok":
+      SimpleTest.ok(msg.data.condition, msg.data.description);
+      return;
+    case "finish":
+      SimpleTest.finish();
+      return;
+    case "value":
+      SimpleTest.ok(true, "test_osfile_comms.xul: Received value " + JSON.stringify(msg.data.value));
+      let type = eval(msg.data.typename);
+      let check = eval(msg.data.check);
+      let value = msg.data.value;
+      let deserialized = type.fromMsg(value);
+      check(deserialized, "Main thread test: ");
+      return;
+    default:
+      SimpleTest.ok(false, "test_osfile_comms.xul: wrong message "+JSON.stringify(msg.data));
+      return;
+    }
+  };
+
+  worker.postMessage(0)
+  ok(true, "Worker launched");
+};
+]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display:none;"></div>
+    <pre id="test"></pre>
+  </body>
+  <label id="test-result"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/osfile/tests/mochi/worker_test_osfile_comms.js
@@ -0,0 +1,147 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function log(text) {
+  dump("WORKER "+text+"\n");
+}
+
+function send(message) {
+  self.postMessage(message);
+}
+
+function finish() {
+  send({kind: "finish"});
+}
+
+function ok(condition, description) {
+  send({kind: "ok", condition: condition, description:description});
+}
+function is(a, b, description) {
+  let outcome = a == b; // Need to decide outcome here, as not everything can be serialized
+  send({kind: "is", outcome: outcome, description: description, a:""+a, b:""+b});
+}
+function isnot(a, b, description) {
+  let outcome = a != b; // Need to decide outcome here, as not everything can be serialized
+  send({kind: "isnot", outcome: outcome, description: description, a:""+a, b:""+b});
+}
+
+// The set of samples for communications test. Declare as a global
+// variable to prevent this from being garbage-collected too early.
+let samples;
+
+self.onmessage = function(msg) {
+  ok(true, "Initializing");
+  self.onmessage = function on_unexpected_message(msg) {
+    throw new Error("Unexpected message " + JSON.stringify(msg.data));
+  };
+  importScripts("resource:///modules/osfile.jsm");
+  ok(true, "Initialization complete");
+
+  samples = [
+    { typename: "OS.Shared.Type.char.in_ptr",
+      valuedescr: "String",
+      value: "This is a test",
+      type: OS.Shared.Type.char.in_ptr,
+      check: function check_string(candidate, prefix) {
+        is(candidate, "This is a test", prefix);
+      }},
+    { typename: "OS.Shared.Type.char.in_ptr",
+      valuedescr: "ArrayBuffer",
+      value: (function() {
+                let buf = new ArrayBuffer(15);
+                let view = new Uint8Array(buf);
+                for (let i = 0; i < 15; ++i) {
+                  view[i] = i;
+                }
+                return buf;
+              })(),
+      type: OS.Shared.Type.char.in_ptr,
+      check: function check_ArrayBuffer(candidate, prefix) {
+        let cast = ctypes.cast(candidate, ctypes.uint8_t.ptr);
+        for (let i = 0; i < 15; ++i) {
+          is(cast.contents, i % 256, prefix + "Checking that the contents of the ArrayBuffer were preserved");
+          cast = cast.increment();
+        }
+      }},
+    { typename: "OS.Shared.Type.char.in_ptr",
+      valuedescr: "Pointer",
+      value: new OS.Shared.Type.char.in_ptr.implementation(1),
+      type: OS.Shared.Type.char.in_ptr,
+      check: function check_ptr(candidate, prefix) {
+        let address = ctypes.cast(candidate, ctypes.uintptr_t).value.toString();
+        is(address, "1", prefix + "Checking that the pointer address was preserved");
+      }},
+    { typename: "OS.Shared.Type.char.in_ptr",
+      valuedescr: "C array",
+      value: (function() {
+                let buf = new (ctypes.ArrayType(ctypes.uint8_t, 15))();
+                for (let i = 0; i < 15; ++i) {
+                  buf[i] = i % 256;
+                }
+                return buf;
+              })(),
+      type: OS.Shared.Type.char.in_ptr,
+      check: function check_array(candidate, prefix) {
+        let cast = ctypes.cast(candidate, ctypes.uint8_t.ptr);
+        for (let i = 0; i < 15; ++i) {
+          is(cast.contents, i % 256, prefix + "Checking that the contents of the C array were preserved, index " + i);
+          cast = cast.increment();
+        }
+      }
+    }
+  ];
+  samples.forEach(function test(sample) {
+    let type = sample.type;