Bug 1188665 - Make nsIDOMWindowUtils.disableDialogs() disable onbeforeunload dialogs. r=bz
authorDrew Willcoxon <adw@mozilla.com>
Fri, 31 Jul 2015 16:13:01 -0700
changeset 287418 a4f7a655c74a5342146dd02aa042a8a1b8c16c6f
parent 287417 15ef1802114fd28a312362ef43a6bb50111e816c
child 287419 3378f3a3394482ae9f6a0dcab1852e44fdeeac65
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1188665
milestone42.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
Bug 1188665 - Make nsIDOMWindowUtils.disableDialogs() disable onbeforeunload dialogs. r=bz
layout/base/nsDocumentViewer.cpp
layout/base/tests/browser.ini
layout/base/tests/browser_disableDialogs_onbeforeunload.js
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -12,17 +12,16 @@
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsIContent.h"
 #include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentViewerPrint.h"
 #include "nsIDOMBeforeUnloadEvent.h"
 #include "nsIDocument.h"
-#include "nsIDOMWindowUtils.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsStyleSet.h"
 #include "nsIFrame.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsSubDocumentFrame.h"
 
 #include "nsILinkHandler.h"
@@ -64,16 +63,17 @@
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
 #include "nsXULPopupManager.h"
 #endif
 
 #include "nsIClipboardHelper.h"
 
 #include "nsPIDOMWindow.h"
+#include "nsGlobalWindow.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsPIWindowRoot.h"
 #include "nsJSEnvironment.h"
 #include "nsFocusManager.h"
 
 #include "nsIScrollableFrame.h"
 #include "nsStyleSheetService.h"
 #include "nsRenderingContext.h"
@@ -1110,41 +1110,41 @@ nsDocumentViewer::PermitUnloadInternal(b
   // Dispatching to |window|, but using |document| as the target.
   event->SetTarget(mDocument);
   event->SetTrusted(true);
 
   // In evil cases we might be destroyed while handling the
   // onbeforeunload event, don't let that happen. (see also bug#331040)
   nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
 
+  bool dialogsAreEnabled = false;
   {
     // Never permit popups from the beforeunload handler, no matter
     // how we get here.
     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
     // Never permit dialogs from the beforeunload handler
-    nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
-    bool dialogsWereEnabled = false;
-    utils->AreDialogsEnabled(&dialogsWereEnabled);
-    utils->DisableDialogs();
+    nsGlobalWindow *globalWindow = static_cast<nsGlobalWindow*>(window);
+    dialogsAreEnabled = globalWindow->AreDialogsEnabled();
+    globalWindow->DisableDialogs();
 
     mInPermitUnload = true;
     EventDispatcher::DispatchDOMEvent(window, nullptr, event, mPresContext,
                                       nullptr);
     mInPermitUnload = false;
-    if (dialogsWereEnabled) {
-      utils->EnableDialogs();
+    if (dialogsAreEnabled) {
+      globalWindow->EnableDialogs();
     }
   }
 
   nsCOMPtr<nsIDocShell> docShell(mContainer);
   nsAutoString text;
   beforeUnload->GetReturnValue(text);
 
-  if (!sIsBeforeUnloadDisabled && *aShouldPrompt &&
+  if (!sIsBeforeUnloadDisabled && *aShouldPrompt && dialogsAreEnabled &&
       (event->GetInternalNSEvent()->mFlags.mDefaultPrevented ||
        !text.IsEmpty())) {
     // Ask the user if it's ok to unload the current page
 
     nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShell);
 
     if (prompt) {
       nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
--- a/layout/base/tests/browser.ini
+++ b/layout/base/tests/browser.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 
 [browser_bug617076.js]
 skip-if = e10s # Bug ?????? - test touches content (TypeError: doc.documentElement is null)
+[browser_disableDialogs_onbeforeunload.js]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/browser_disableDialogs_onbeforeunload.js
@@ -0,0 +1,54 @@
+function pageScript() {
+  window.addEventListener("beforeunload", function (event) {
+    var str = "Some text that causes the beforeunload dialog to be shown";
+    event.returnValue = str;
+    return str;
+  }, true);
+}
+
+const PAGE_URL =
+  "data:text/html," + encodeURIComponent("<script>(" + pageScript.toSource() + ")();</script>");
+
+add_task(function* enableDialogs() {
+  // The onbeforeunload dialog should appear.
+  let dialogShown = false;
+  function onDialogShown(node) {
+    dialogShown = true;
+    let dismissButton = node.ui.button0;
+    dismissButton.click();
+  }
+  let obsName = "tabmodal-dialog-loaded";
+  Services.obs.addObserver(onDialogShown, obsName, false);
+  yield openPage(true);
+  Services.obs.removeObserver(onDialogShown, obsName);
+  Assert.ok(dialogShown);
+});
+
+add_task(function* disableDialogs() {
+  // The onbeforeunload dialog should NOT appear.
+  yield openPage(false);
+  info("If we time out here, then the dialog was shown...");
+});
+
+function* openPage(enableDialogs) {
+  // Open about:blank in a new tab.
+  yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, function* (browser) {
+    // Load the content script in the frame.
+    let methodName = enableDialogs ? "enableDialogs" : "disableDialogs";
+    yield ContentTask.spawn(browser, methodName, function* (name) {
+      Components.utils.import("resource://gre/modules/Services.jsm");
+      Services.obs.addObserver(doc => {
+        if (content && doc == content.document) {
+          content.QueryInterface(Ci.nsIInterfaceRequestor).
+            getInterface(Ci.nsIDOMWindowUtils)[name]();
+        }
+      }, "document-element-inserted", false);
+    });
+    // Load the page.
+    yield BrowserTestUtils.loadURI(browser, PAGE_URL);
+    yield BrowserTestUtils.browserLoaded(browser);
+    // And then navigate away.
+    yield BrowserTestUtils.loadURI(browser, "http://example.com/");
+    yield BrowserTestUtils.browserLoaded(browser);
+  });
+}