Bug 990475 - Add WebIDL APIs for WindowModal. r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Wed, 05 Feb 2014 22:09:18 +0100
changeset 177548 4fbe5c6db77386bc98efd3a43b78061c48575b2d
parent 177547 de6943d52d81efa91c0155e945ab4e00cb0a964c
child 177549 72b4d4463629780dcf5733aea3bbce8fd8b64907
push id26556
push userryanvm@gmail.com
push dateTue, 08 Apr 2014 22:16:57 +0000
treeherdermozilla-central@5811efc11011 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs990475
milestone31.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 990475 - Add WebIDL APIs for WindowModal. r=bz.
content/media/webspeech/synth/test/file_setup.html
content/media/webspeech/synth/test/file_speech_queue.html
content/media/webspeech/synth/test/file_speech_simple.html
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/tests/mochitest/general/file_showModalDialog.html
dom/webidl/Window.webidl
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1717,16 +1717,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
 
 #ifdef MOZ_WEBSPEECH
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
 #endif
 
@@ -1774,16 +1775,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
   nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
 
 #ifdef MOZ_WEBSPEECH
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
 #endif
 
@@ -13416,66 +13418,135 @@ nsGlobalWindow::GetMessageManager(ErrorR
                                 MM_CHROME | MM_BROADCASTER);
   }
   return myself->mMessageManager;
 }
 
 // nsGlobalModalWindow implementation
 
 // QueryInterface implementation for nsGlobalModalWindow
-NS_IMPL_CYCLE_COLLECTION_INHERITED_1(nsGlobalModalWindow,
-                                     nsGlobalWindow,
-                                     mReturnValue)
-
 DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
+NS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)
   NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
 
 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 
 
+JS::Value
+nsGlobalWindow::GetDialogArguments(JSContext* aCx, ErrorResult& aError)
+{
+  FORWARD_TO_OUTER_OR_THROW(GetDialogArguments, (aCx, aError), aError,
+                            JS::UndefinedValue());
+
+  MOZ_ASSERT(IsModalContentWindow(),
+             "This should only be called on modal windows!");
+
+  // This does an internal origin check, and returns undefined if the subject
+  // does not subsumes the origin of the arguments.
+  JSObject* wrapper = GetWrapper();
+  JSAutoCompartment ac(aCx, wrapper);
+  JS::Rooted<JS::Value> args(aCx);
+  mDialogArguments->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
+                        &args, aError);
+  return args;
+}
+
 NS_IMETHODIMP
 nsGlobalModalWindow::GetDialogArguments(nsIVariant **aArguments)
 {
   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
                                         NS_ERROR_NOT_INITIALIZED);
 
   // This does an internal origin check, and returns undefined if the subject
   // does not subsumes the origin of the arguments.
   return mDialogArguments->Get(nsContentUtils::GetSubjectPrincipal(), aArguments);
 }
 
+JS::Value
+nsGlobalWindow::GetReturnValue(JSContext* aCx, ErrorResult& aError)
+{
+  FORWARD_TO_OUTER_OR_THROW(GetReturnValue, (aCx, aError), aError,
+                            JS::UndefinedValue());
+
+  MOZ_ASSERT(IsModalContentWindow(),
+             "This should only be called on modal windows!");
+
+  JS::Rooted<JS::Value> returnValue(aCx);
+  if (mReturnValue) {
+    JSObject* wrapper = GetWrapper();
+    JSAutoCompartment ac(aCx, wrapper);
+    mReturnValue->Get(aCx, wrapper, nsContentUtils::GetSubjectPrincipal(),
+                      &returnValue, aError);
+  }
+  return returnValue;
+}
+
 NS_IMETHODIMP
 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
 {
   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
 
   nsCOMPtr<nsIVariant> result;
   if (!mReturnValue) {
     nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
     variant.forget(aRetVal);
     return NS_OK;
   }
   return mReturnValue->Get(nsContentUtils::GetSubjectPrincipal(), aRetVal);
 }
 
+void
+nsGlobalWindow::SetReturnValue(JSContext* aCx,
+                               JS::Handle<JS::Value> aReturnValue,
+                               ErrorResult& aError)
+{
+  FORWARD_TO_OUTER_OR_THROW(SetReturnValue, (aCx, aReturnValue, aError),
+                            aError, );
+
+  MOZ_ASSERT(IsModalContentWindow(),
+             "This should only be called on modal windows!");
+
+  nsCOMPtr<nsIVariant> returnValue;
+  aError =
+    nsContentUtils::XPConnect()->JSToVariant(aCx, aReturnValue,
+                                             getter_AddRefs(returnValue));
+  if (!aError.Failed()) {
+    mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
+                                         returnValue);
+  }
+}
+
 NS_IMETHODIMP
 nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
 {
   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
 
   mReturnValue = new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(),
                                        aRetVal);
   return NS_OK;
 }
 
+/* static */
+bool
+nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
+{
+  // For now, have to deal with XPConnect objects here.
+  nsGlobalWindow* win;
+  nsresult rv = UNWRAP_OBJECT(Window, aGlobal, win);
+  if (NS_FAILED(rv)) {
+    nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrapper(aCx, aGlobal);
+    win = static_cast<nsGlobalWindow*>(piWin.get());
+  }
+  return win->IsModalContentWindow();
+}
+
 NS_IMETHODIMP
 nsGlobalWindow::GetConsole(JSContext* aCx,
                            JS::MutableHandle<JS::Value> aConsole)
 {
   ErrorResult rv;
   nsRefPtr<Console> console = GetConsole(rv);
   if (rv.Failed()) {
     return rv.ErrorCode();
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -272,16 +272,26 @@ public:
     if (aSubject->SubsumesConsideringDomain(mOrigin)) {
       result = mValue;
     } else {
       result = CreateVoidVariant();
     }
     result.forget(aResult);
     return NS_OK;
   }
+  void Get(JSContext* aCx, JSObject* aScope, nsIPrincipal* aSubject,
+           JS::MutableHandle<JS::Value> aResult, mozilla::ErrorResult& aError)
+  {
+    if (aSubject->Subsumes(mOrigin)) {
+      aError = nsContentUtils::XPConnect()->VariantToJS(aCx, aScope,
+                                                        mValue, aResult);
+    } else {
+      aResult.setUndefined();
+    }
+  }
   virtual ~DialogValueHolder() {}
 private:
   nsCOMPtr<nsIPrincipal> mOrigin;
   nsCOMPtr<nsIVariant> mValue;
 };
 
 //*****************************************************************************
 // nsGlobalWindow: Global Object for Scripting
@@ -576,16 +586,19 @@ public:
     return  mCreatingInnerWindow;
   }
 
   bool IsChromeWindow() const
   {
     return mIsChrome;
   }
 
+  using nsPIDOMWindow::IsModalContentWindow;
+  static bool IsModalContentWindow(JSContext* aCx, JSObject* aGlobal);
+
   // GetScrollFrame does not flush.  Callers should do it themselves as needed,
   // depending on which info they actually want off the scrollable frame.
   nsIScrollableFrame *GetScrollFrame();
 
   nsresult Observe(nsISupports* aSubject, const char* aTopic,
                    const char16_t* aData);
 
   // Outer windows only.
@@ -977,16 +990,21 @@ public:
   void Restore(mozilla::ErrorResult& aError);
   void NotifyDefaultButtonLoaded(mozilla::dom::Element& aDefaultButton,
                                  mozilla::ErrorResult& aError);
   nsIMessageBroadcaster* GetMessageManager(mozilla::ErrorResult& aError);
   void BeginWindowMove(mozilla::dom::Event& aMouseDownEvent,
                        mozilla::dom::Element* aPanel,
                        mozilla::ErrorResult& aError);
 
+  JS::Value GetDialogArguments(JSContext* aCx, mozilla::ErrorResult& aError);
+  JS::Value GetReturnValue(JSContext* aCx, mozilla::ErrorResult& aError);
+  void SetReturnValue(JSContext* aCx, JS::Handle<JS::Value> aReturnValue,
+                      mozilla::ErrorResult& aError);
+
 protected:
   // Array of idle observers that are notified of idle events.
   nsTObserverArray<IdleObserverHolder> mIdleObservers;
 
   // Idle timer used for function callbacks to notify idle observers.
   nsCOMPtr<nsITimer> mIdleTimer;
 
   // Idle fuzz time added to idle timer callbacks.
@@ -1435,16 +1453,19 @@ protected:
   nsCOMPtr<nsIControllers>      mControllers;
 
   // For |window.arguments|, via |openDialog|.
   nsCOMPtr<nsIArray>            mArguments;
 
   // For |window.dialogArguments|, via |showModalDialog|.
   nsRefPtr<DialogValueHolder> mDialogArguments;
 
+  // Only used in the outer.
+  nsRefPtr<DialogValueHolder> mReturnValue;
+
   nsRefPtr<mozilla::dom::Navigator> mNavigator;
   nsRefPtr<nsScreen>            mScreen;
   nsRefPtr<nsDOMWindowList>     mFrames;
   nsRefPtr<mozilla::dom::BarProp> mMenubar;
   nsRefPtr<mozilla::dom::BarProp> mToolbar;
   nsRefPtr<mozilla::dom::BarProp> mLocationbar;
   nsRefPtr<mozilla::dom::BarProp> mPersonalbar;
   nsRefPtr<mozilla::dom::BarProp> mStatusbar;
@@ -1634,22 +1655,16 @@ public:
   nsGlobalModalWindow(nsGlobalWindow *aOuterWindow)
     : nsGlobalWindow(aOuterWindow)
   {
     mIsModalContentWindow = true;
   }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMMODALCONTENTWINDOW
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
-
-protected:
-  // For use by outer windows only.
-  nsRefPtr<DialogValueHolder> mReturnValue;
 };
 
 /* factory function */
 inline already_AddRefed<nsGlobalWindow>
 NS_NewScriptGlobalObject(bool aIsChrome, bool aIsModalContentWindow)
 {
   nsRefPtr<nsGlobalWindow> global;
 
--- a/dom/tests/mochitest/general/file_showModalDialog.html
+++ b/dom/tests/mochitest/general/file_showModalDialog.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html>
 <head>
 <script>
   function go() {
     is(SpecialPowers.wrap(window).location.toString(), location.toString(), "sanity");
-    is(SpecialPowers.Cu.getClassName(window, /* aUnwrap = */ true), "ModalContentWindow", "We are modal");
+    ok("returnValue" in window && "dialogArguments" in window, "We are modal");
     var iwin = document.getElementById('ifr').contentWindow;
     is(SpecialPowers.Cu.getClassName(iwin, /* aUnwrap = */ true), "Window", "Descendant frames should not be modal");
 
     if (location.origin != "http://mochi.test:8888") {
       is(window.dialogArguments, undefined,
         "dialogArguments should be undefined cross-origin: " + location.origin);
     }
 
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -220,16 +220,24 @@ partial interface Window {
 [NoInterfaceObject]
 interface SpeechSynthesisGetter {
   [Throws, Pref="media.webspeech.synth.enabled"] readonly attribute SpeechSynthesis speechSynthesis;
 };
 
 Window implements SpeechSynthesisGetter;
 #endif
 
+// http://www.whatwg.org/specs/web-apps/current-work/
+[NoInterfaceObject]
+interface WindowModal {
+  [Throws, Func="nsGlobalWindow::IsModalContentWindow"] readonly attribute any dialogArguments;
+  [Throws, Func="nsGlobalWindow::IsModalContentWindow"] attribute any returnValue;
+};
+Window implements WindowModal;
+
 // Mozilla-specific stuff
 partial interface Window {
   //[NewObject, Throws] CSSStyleDeclaration getDefaultComputedStyle(Element elt, optional DOMString pseudoElt = "");
   [NewObject, Throws] CSSStyleDeclaration? getDefaultComputedStyle(Element elt, optional DOMString pseudoElt = "");
 
   [Throws] long mozRequestAnimationFrame(MozFrameRequestCallback aCallback);
 
   /**