Bug 1004458 - Maintain modal state on outer windows only instead of relying on forwarding from inner to outer. r=peterv, a=sledru
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 15 May 2014 10:26:23 -0700
changeset 192322 4ffac6a8ab14
parent 192321 8104a9e1bfaf
child 192323 35fe7342d5aa
push id3567
push userryanvm@gmail.com
push date2014-05-20 15:05 +0000
Treeherderresults
reviewerspeterv, sledru
bugs1004458
milestone30.0
Bug 1004458 - Maintain modal state on outer windows only instead of relying on forwarding from inner to outer. r=peterv, a=sledru
dom/base/nsGlobalWindow.cpp
embedding/components/windowwatcher/src/nsAutoWindowStateHelper.cpp
embedding/components/windowwatcher/src/nsAutoWindowStateHelper.h
embedding/components/windowwatcher/src/nsWindowWatcher.cpp
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8331,17 +8331,17 @@ nsGlobalWindow::ReallyCloseWindow()
 
     CleanUp();
   }
 }
 
 void
 nsGlobalWindow::EnterModalState()
 {
-  FORWARD_TO_OUTER_VOID(EnterModalState, ());
+  MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
 
   // GetScriptableTop, not GetTop, so that EnterModalState works properly with
   // <iframe mozbrowser>.
   nsGlobalWindow* topWin = GetScriptableTop();
 
   if (!topWin) {
     NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
     return;
@@ -8463,17 +8463,17 @@ public:
 
 private:
   nsRefPtr<nsGlobalWindow> mWindow;
 };
 
 void
 nsGlobalWindow::LeaveModalState()
 {
-  FORWARD_TO_OUTER_VOID(LeaveModalState, ());
+  MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
 
   nsGlobalWindow* topWin = GetScriptableTop();
 
   if (!topWin) {
     NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
     return;
   }
 
--- a/embedding/components/windowwatcher/src/nsAutoWindowStateHelper.cpp
+++ b/embedding/components/windowwatcher/src/nsAutoWindowStateHelper.cpp
@@ -14,61 +14,58 @@
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 /****************************************************************
  ****************** nsAutoWindowStateHelper *********************
  ****************************************************************/
 
-nsAutoWindowStateHelper::nsAutoWindowStateHelper(nsIDOMWindow *aWindow)
+nsAutoWindowStateHelper::nsAutoWindowStateHelper(nsPIDOMWindow *aWindow)
   : mWindow(aWindow),
     mDefaultEnabled(DispatchEventToChrome("DOMWillOpenModalDialog"))
 {
-  nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
-
-  if (window) {
-    window->EnterModalState();
+  if (mWindow) {
+    mWindow->EnterModalState();
   }
 }
 
 nsAutoWindowStateHelper::~nsAutoWindowStateHelper()
 {
-  nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mWindow));
-
-  if (window) {
-    window->LeaveModalState();
+  if (mWindow) {
+    mWindow->LeaveModalState();
   }
 
   if (mDefaultEnabled) {
     DispatchEventToChrome("DOMModalDialogClosed");
   }
 }
 
 bool
 nsAutoWindowStateHelper::DispatchEventToChrome(const char *aEventName)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mWindow);
-  if (!window || (window->IsInnerWindow() && !window->IsCurrentInnerWindow())) {
+  // XXXbz should we skip dispatching the event if the inner changed?
+  // That is, should we store both the inner and the outer?
+  if (!mWindow) {
     return true;
   }
 
   // The functions of nsContentUtils do not provide the required behavior,
   // so the following is inlined.
-  nsIDocument* doc = window->GetExtantDoc();
+  nsIDocument* doc = mWindow->GetExtantDoc();
   if (!doc) {
     return true;
   }
 
   ErrorResult rv;
   nsRefPtr<Event> event = doc->CreateEvent(NS_LITERAL_STRING("Events"), rv);
   if (rv.Failed()) {
     return false;
   }
   NS_ENSURE_TRUE(NS_SUCCEEDED(event->InitEvent(NS_ConvertASCIItoUTF16(aEventName), true, true)), false);
   event->SetTrusted(true);
   event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
 
-  nsCOMPtr<EventTarget> target = do_QueryInterface(window);
+  nsCOMPtr<EventTarget> target = do_QueryInterface(mWindow);
   bool defaultActionEnabled;
   target->DispatchEvent(event, &defaultActionEnabled);
   return defaultActionEnabled;
 }
--- a/embedding/components/windowwatcher/src/nsAutoWindowStateHelper.h
+++ b/embedding/components/windowwatcher/src/nsAutoWindowStateHelper.h
@@ -2,36 +2,37 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __nsAutoWindowStateHelper_h
 #define __nsAutoWindowStateHelper_h
 
 #include "nsCOMPtr.h"
+#include "nsPIDOMWindow.h"
 
 /**
  * Helper class for dealing with notifications around opening modal
  * windows.
  */
 
-class nsIDOMWindow;
+class nsPIDOMWindow;
 
 class nsAutoWindowStateHelper
 {
 public:
-  nsAutoWindowStateHelper(nsIDOMWindow *aWindow);
+  nsAutoWindowStateHelper(nsPIDOMWindow *aWindow);
   ~nsAutoWindowStateHelper();
 
   bool DefaultEnabled()
   {
     return mDefaultEnabled;
   }
 
 protected:
   bool DispatchEventToChrome(const char *aEventName);
 
-  nsIDOMWindow *mWindow;
+  nsCOMPtr<nsPIDOMWindow> mWindow;
   bool mDefaultEnabled;
 };
 
 
 #endif
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
@@ -951,17 +951,21 @@ nsWindowWatcher::OpenWindowInternal(nsID
     // Throw an exception here if no web browser chrome is available,
     // we need that to show a modal window.
     NS_ENSURE_TRUE(newChrome, NS_ERROR_NOT_AVAILABLE);
 
     // Dispatch dialog events etc, but we only want to do that if
     // we're opening a modal content window (the helper classes are
     // no-ops if given no window), for chrome dialogs we don't want to
     // do any of that (it's done elsewhere for us).
-    nsAutoWindowStateHelper windowStateHelper(aParent);
+    // Make sure we maintain the state on an outer window, because
+    // that's where it lives; inner windows assert if you try to
+    // maintain the state on them.
+    nsAutoWindowStateHelper windowStateHelper(
+      parentWindow ? parentWindow->GetOuterWindow() : nullptr);
 
     if (!windowStateHelper.DefaultEnabled()) {
       // Default to cancel not opening the modal window.
       NS_RELEASE(*_retval);
 
       return NS_OK;
     }