[mq]: modal1b.patch
authorPeter Van der Beken <peterv@propagandism.org>
Sat, 15 Feb 2014 22:12:16 +0100
changeset 171891 23bdcdc2c8cee8297c547ae6fc1a7af6ee9db683
parent 171890 6f35c94260aade25961d07b73b48a262a4117bea
child 171892 26889538becc5a98115762eb4adda0c0a07cfc59
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
[mq]: modal1b.patch
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/interfaces/base/nsIDOMModalContentWindow.idl
dom/interfaces/base/nsIDOMWindow.idl
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1696,16 +1696,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
 
@@ -1753,16 +1754,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
 
@@ -1831,17 +1833,16 @@ TraceXBLHandlers(nsXBLPrototypeHandler* 
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
   if (tmp->mCachedXBLPrototypeHandlers) {
     TraceData data = { aCallbacks, aClosure };
     tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
   }
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mReturnValue.mValue)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 bool
 nsGlobalWindow::IsBlackForCC(bool aTracingNeeded)
 {
   if (!nsCCUncollectableMarker::sGeneration) {
     return false;
@@ -8718,49 +8719,48 @@ ConvertDialogOptions(const nsAString& aO
     if (iter == end) {
       break;
     }
 
     iter++;
   }
 }
 
-JS::Value
+already_AddRefed<nsIVariant>
 nsGlobalWindow::ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
-                                const nsAString& aOptions,
-                                ErrorResult& aError)
+                                const nsAString& aOptions, ErrorResult& aError)
 {
   if (mDoc) {
     mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog);
   }
 
   FORWARD_TO_OUTER_OR_THROW(ShowModalDialog,
                             (aUrl, aArgument, aOptions, aError), aError,
-                            JS::UndefinedValue());
+                            nullptr);
 
   if (Preferences::GetBool("dom.disable_window_showModalDialog", false)) {
     aError.Throw(NS_ERROR_NOT_AVAILABLE);
-    return JS::UndefinedValue();
+    return nullptr;
   }
 
   nsRefPtr<DialogValueHolder> argHolder =
     new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(), aArgument);
 
   // Before bringing up the window/dialog, unsuppress painting and flush
   // pending reflows.
   EnsureReflowFlushAndPaint();
 
   if (!AreDialogsEnabled()) {
     aError.Throw(NS_ERROR_NOT_AVAILABLE);
-    return JS::UndefinedValue();
+    return nullptr;
   }
 
   if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
     aError.Throw(NS_ERROR_NOT_AVAILABLE);
-    return JS::UndefinedValue();
+    return nullptr;
   }
 
   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");
@@ -8776,62 +8776,76 @@ nsGlobalWindow::ShowModalDialog(const ns
                         true,           // aNavigate
                         nullptr, argHolder, // args
                         GetPrincipal(),     // aCalleePrincipal
                         nullptr,            // aJSCallerContext
                         getter_AddRefs(dlgWin));
   nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel);
   LeaveModalState();
   if (aError.Failed()) {
-    return JS::UndefinedValue();
-  }
-
-  nsCOMPtr<nsISupports> winSupports = do_QueryInterface(dlgWin);
-  if (!winSupports) {
-    return JS::NullValue();
-  }
-
-  return nsGlobalWindow::FromSupports(winSupports)->GetReturnValue(aError);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDOMModalContentWindow> dialog = do_QueryInterface(dlgWin);
+  if (!dialog) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIVariant> retVal;
+  aError = dialog->GetReturnValue(getter_AddRefs(retVal));
+  MOZ_ASSERT(!aError.Failed());
+
+  return retVal.forget();
 }
 
 JS::Value
 nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
                                 JS::Handle<JS::Value> aArgument,
                                 const nsAString& aOptions,
                                 ErrorResult& aError)
 {
   nsCOMPtr<nsIVariant> args;
   aError = nsContentUtils::XPConnect()->JSToVariant(aCx,
                                                     aArgument,
                                                     getter_AddRefs(args));
 
-  return ShowModalDialog(aUrl, args, aOptions, aError);
+  nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aUrl, args, aOptions, aError);
+  if (aError.Failed()) {
+    return JS::UndefinedValue();
+  }
+
+  JS::Rooted<JS::Value> result(aCx);
+  if (retVal) {
+    aError = nsContentUtils::XPConnect()->VariantToJS(aCx,
+                                                      FastGetGlobalJSObject(),
+                                                      retVal, &result);
+  } else {
+    result = JS::NullValue();
+  }
+  return result;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs_,
-                                const nsAString& aOptions, JSContext* aCx,
-                                uint8_t aArgc, nsIVariant **aRetVal)
+                                const nsAString& aOptions, uint8_t aArgc,
+                                nsIVariant **aRetVal)
 {
   // Per-spec the |arguments| parameter is supposed to pass through unmodified.
   // However, XPConnect default-initializes variants to null, rather than
   // undefined. Fix this up here.
   nsCOMPtr<nsIVariant> aArgs = aArgs_;
   if (aArgc < 1) {
     aArgs = CreateVoidVariant();
   }
 
   ErrorResult rv;
-  JS::Rooted<JS::Value> returnValue(aCx,
-                                    ShowModalDialog(aURI, aArgs, aOptions, rv));
-  if (rv.Failed()) {
-    return rv.ErrorCode();
-  }
-
-  return nsContentUtils::XPConnect()->JSToVariant(aCx, returnValue, aRetVal);
+  nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aURI, aArgs, aOptions, rv);
+  retVal.forget(aRetVal);
+
+  return rv.ErrorCode();
 }
 
 class CommandDispatcher : public nsRunnable
 {
 public:
   CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
                     const nsAString& aAction)
   : mDispatcher(aDispatcher), mAction(aAction) {}
@@ -13297,77 +13311,75 @@ nsGlobalModalWindow::GetDialogArguments(
                                         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(ErrorResult& aError)
-{
-  FORWARD_TO_OUTER_OR_THROW(GetReturnValue, (aError), aError,
+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!");
 
-  return mReturnValue.Get(nsContentUtils::GetSubjectPrincipal());
-}
-
-NS_IMETHODIMP
-nsGlobalModalWindow::GetReturnValue(JSContext* aCx, nsIVariant **aRetVal)
-{
-  ErrorResult rv;
-  JS::Rooted<JS::Value> returnValue(aCx,
-                                    nsGlobalWindow::GetReturnValue(rv));
-  if (rv.Failed()) {
-    return rv.ErrorCode();
-  }
-
-  if (returnValue.isNull()) {
+  JS::Rooted<JS::Value> returnValue(aCx);
+  if (mReturnValue) {
+    mReturnValue->Get(aCx, GetWrapper(), 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 nsContentUtils::XPConnect()->JSToVariant(aCx, returnValue, aRetVal);
+  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!");
 
-  mReturnValue.Set(nsContentUtils::GetSubjectPrincipal(), aReturnValue);
-  PreserveWrapper(ToSupports(this));
-}
-
-NS_IMETHODIMP
-nsGlobalModalWindow::SetReturnValue(JSContext* aCx, nsIVariant *aRetVal)
-{
-  FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aCx, aRetVal), NS_OK);
-
-  ErrorResult rv;
-  JS::Rooted<JS::Value> returnValue(aCx);
-  rv = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), aRetVal,
-                                                &returnValue);
-  if (!rv.Failed()) {
-    mReturnValue.Set(nsContentUtils::GetSubjectPrincipal(), returnValue);
-    PreserveWrapper(ToSupports(this));
-  }
-
-  return rv.ErrorCode();
+  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)
 {
   nsGlobalWindow* win;
   UNWRAP_OBJECT(Window, aGlobal, win);
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -286,38 +286,16 @@ public:
     }
   }
   virtual ~DialogValueHolder() {}
 private:
   nsCOMPtr<nsIPrincipal> mOrigin;
   nsCOMPtr<nsIVariant> mValue;
 };
 
-// Helper class to manage modal dialog return value. We need to track both the
-// returned value as well as the caller's principal, so that we can do an origin
-// check (even for primitives) when the value is accessed.
-struct DialogReturnValueHolder
-{
-  JS::Value Get(nsIPrincipal* aSubject)
-  {
-    if (aSubject->Subsumes(mOrigin)) {
-      return JS::UndefinedValue();
-    }
-    return mValue;
-  }
-  void Set(nsIPrincipal* aOrigin, JS::Handle<JS::Value> aReturnValue)
-  {
-    mOrigin = aOrigin;
-    mValue = aReturnValue;
-  }
-
-  nsCOMPtr<nsIPrincipal> mOrigin;
-  JS::Heap<JS::Value> mValue;
-};
-
 //*****************************************************************************
 // nsGlobalWindow: Global Object for Scripting
 //*****************************************************************************
 // Beware that all scriptable interfaces implemented by
 // nsGlobalWindow will be reachable from JS, if you make this class
 // implement new interfaces you better know what you're
 // doing. Security wise this is very sensitive code. --
 // jst@netscape.com
@@ -1010,20 +988,17 @@ public:
   void NotifyDefaultButtonLoaded(mozilla::dom::Element& aDefaultButton,
                                  mozilla::ErrorResult& aError);
   nsIMessageBroadcaster* GetMessageManager(mozilla::ErrorResult& aError);
   void BeginWindowMove(nsDOMEvent& aMouseDownEvent,
                        mozilla::dom::Element* aPanel,
                        mozilla::ErrorResult& aError);
 
   JS::Value GetDialogArguments(JSContext* aCx, mozilla::ErrorResult& aError);
-  JS::Value GetReturnValue(JSContext* aCx, mozilla::ErrorResult& aError)
-  {
-    return GetReturnValue(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.
@@ -1376,30 +1351,28 @@ protected:
 
   mozilla::dom::Element* GetRealFrameElement(mozilla::ErrorResult& aError);
 
   void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                       const nsAString& aTargetOrigin,
                       JS::Handle<JS::Value> aTransfer,
                       mozilla::ErrorResult& aError);
 
-  JS::Value ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
-                            const nsAString& aOptions,
-                            mozilla::ErrorResult& aError);
+  already_AddRefed<nsIVariant>
+    ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
+                    const nsAString& aOptions, mozilla::ErrorResult& aError);
 
   already_AddRefed<nsIDOMWindow>
     GetContentInternal(mozilla::ErrorResult& aError);
 
   // 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();
 
-  JS::Value GetReturnValue(mozilla::ErrorResult& aError);
-
   // When adding new member variables, be careful not to create cycles
   // through JavaScript.  If there is any chance that a member variable
   // could own objects that are implemented in JavaScript, then those
   // objects will keep the global object (this object) alive.  To prevent
   // these cycles, ownership of such members must be released in
   // |CleanUp| and |DetachFromDocShell|.
 
   // This member is also used on both inner and outer windows, but
@@ -1483,17 +1456,17 @@ protected:
   nsCOMPtr<nsIControllers>      mControllers;
 
   // For |window.arguments|, via |openDialog|.
   nsCOMPtr<nsIArray>            mArguments;
 
   // For |window.dialogArguments|, via |showModalDialog|.
   nsRefPtr<DialogValueHolder> mDialogArguments;
 
-  DialogReturnValueHolder     mReturnValue;
+  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;
--- a/dom/interfaces/base/nsIDOMModalContentWindow.idl
+++ b/dom/interfaces/base/nsIDOMModalContentWindow.idl
@@ -17,11 +17,10 @@ interface nsIDOMModalContentWindow : nsI
    * performed at access time, per spec.
    */
   readonly attribute nsIVariant            dialogArguments;
 
   /**
    * The return value that will be returned to the function that
    * opened the modal content window.
    */
-  [implicit_jscontext]
   attribute nsIVariant                   returnValue;
 };
--- a/dom/interfaces/base/nsIDOMWindow.idl
+++ b/dom/interfaces/base/nsIDOMWindow.idl
@@ -194,17 +194,17 @@ interface nsIDOMWindow : nsISupports
   boolean                   confirm([optional] in DOMString text);
 
   // prompt() should return a null string if cancel is pressed
   DOMString                 prompt([optional] in DOMString aMessage,
                                    [optional] in DOMString aInitial);
 
   void                      print();
 
-  [implicit_jscontext, optional_argc]
+  [optional_argc]
   nsIVariant                showModalDialog(in DOMString aURI,
                                             [optional] in nsIVariant aArgs,
                                             [optional] in DOMString aOptions);
 
 
   // cross-document messaging
   /**
    * Implements a safe message-passing system which can cross same-origin