Bug 875157 (part 2) - prevent background thumbnails from displaying alerts/dialogs. r=adw
authorMark Hammond <mhammond@skippinet.com.au>
Fri, 31 May 2013 11:17:41 +1000
changeset 146500 99fa110edd75e99c60a20b1ec69107a5bdd86ebb
parent 146499 b9c758d2b757b96274d8a32894cf55e7f97c3987
child 146501 0ba36fe91ec1fa914749876cc01bad4c1a0c3a00
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersadw
bugs875157
milestone24.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 875157 (part 2) - prevent background thumbnails from displaying alerts/dialogs. r=adw
toolkit/components/prompts/src/nsPrompter.js
toolkit/components/thumbnails/content/backgroundPageThumbsContent.js
toolkit/components/thumbnails/test/browser_thumbnails_background.js
--- a/toolkit/components/prompts/src/nsPrompter.js
+++ b/toolkit/components/prompts/src/nsPrompter.js
@@ -360,23 +360,38 @@ XPCOMUtils.defineLazyGetter(PromptUtils,
         ellipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
     } catch (e) { }
     return ellipsis;
 });
 
 
 
 function openModalWindow(domWin, uri, args) {
-    // XXX Investigate supressing modal state when we're called without a
-    // window? Seems odd to affect whatever window happens to be active.
-    if (!domWin)
+    // There's an implied contract that says modal prompts should still work
+    // when no "parent" window is passed for the dialog (eg, the "Master
+    // Password" dialog does this).  These prompts must be shown even if there
+    // are *no* visible windows at all.
+    // There's also a requirement for prompts to be blocked if a window is
+    // passed and that window is hidden (eg, auth prompts are supressed if the
+    // passed window is the hidden window).
+    // See bug 875157 comment 30 for more...
+    if (domWin) {
+        // a domWin was passed, so we can apply the check for it being hidden.
+        let winUtils = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                             .getInterface(Ci.nsIDOMWindowUtils);
+        if (!winUtils.isParentWindowMainWidgetVisible) {
+            throw Components.Exception("Cannot call openModalWindow on a hidden window",
+                                       Cr.NS_ERROR_NOT_AVAILABLE);
+        }
+    } else {
+        // We try and find a window to use as the parent, but don't consider
+        // if that is visible before showing the prompt.
         domWin = Services.ww.activeWindow;
-
-    // domWin may still be null here if there are _no_ windows open.
-
+        // domWin may still be null here if there are _no_ windows open.
+    }
     // Note that we don't need to fire DOMWillOpenModalDialog and
     // DOMModalDialogClosed events here, wwatcher's OpenWindowInternal
     // will do that. Similarly for enterModalState / leaveModalState.
 
     Services.ww.openWindow(domWin, uri, "_blank", "centerscreen,chrome,modal,titlebar", args);
 }
 
 function openTabPrompt(domWin, tabPrompt, args) {
--- a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js
+++ b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js
@@ -6,16 +6,23 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/PageThumbs.jsm");
 
 const backgroundPageThumbsContent = {
 
   init: function () {
+    // Arrange to prevent (most) popup dialogs for this window - popups done
+    // in the parent (eg, auth) aren't prevented, but alert() etc are.
+    let dwu = content.
+                QueryInterface(Ci.nsIInterfaceRequestor).
+                getInterface(Ci.nsIDOMWindowUtils);
+    dwu.preventFurtherDialogs();
+
     // Stop about:blank from loading.  If it finishes loading after a capture
     // request is received, it could trigger the capture's load listener.
     this._webNav.stop(Ci.nsIWebNavigation.STOP_NETWORK);
     addMessageListener("BackgroundPageThumbs:capture",
                        this._onCapture.bind(this));
   },
 
   get _webNav() {
--- a/toolkit/components/thumbnails/test/browser_thumbnails_background.js
+++ b/toolkit/components/thumbnails/test/browser_thumbnails_background.js
@@ -222,20 +222,53 @@ let tests = [
     let file = fileForURL(url);
     ok(file.exists(), "Thumbnail file should exist after capture.");
 
     let deferred = imports.Promise.defer();
     retrieveImageDataForURL(url, function ([r, g, b]) {
       isnot([r, g, b].toString(), [0, 255, 0].toString(),
             "The captured page should not be green.");
       gBrowser.removeTab(tab);
+      file.remove(false);
       deferred.resolve();
     });
     yield deferred.promise;
   },
+
+  // the following tests attempt to display modal dialogs.  The test just
+  // relies on the fact that if the dialog was displayed the test will hang
+  // and timeout.  IOW - the tests would pass if the dialogs appear and are
+  // manually closed by the user - so don't do that :)  (obviously there is
+  // noone available to do that when run via tbpl etc, so this should be safe,
+  // and it's tricky to use the window-watcher to check a window *does not*
+  // appear - how long should the watcher be active before assuming it's not
+  // going to appear?)
+  function noAuthPrompt() {
+    let url = "http://mochi.test:8888/browser/browser/base/content/test/authenticate.sjs?user=anyone";
+    let file = fileForURL(url);
+    ok(!file.exists(), "Thumbnail file should not already exist.");
+
+    let capturedURL = yield capture(url);
+    is(capturedURL, url, "Captured URL should be URL passed to capture.");
+    ok(file.exists(),
+       "Thumbnail file should exist even though it requires auth.");
+    file.remove(false);
+  },
+
+  function noAlert() {
+    let url = "data:text/html,<script>alert('yo!');</script>";
+    let file = fileForURL(url);
+    ok(!file.exists(), "Thumbnail file should not already exist.");
+
+    let capturedURL = yield capture(url);
+    is(capturedURL, url, "Captured URL should be URL passed to capture.");
+    ok(file.exists(),
+       "Thumbnail file should exist even though it alerted.");
+    file.remove(false);
+  },
 ];
 
 function capture(url, options) {
   let deferred = imports.Promise.defer();
   options = options || {};
   options.onDone = function onDone(capturedURL) {
     deferred.resolve(capturedURL);
   };