diff --git a/dom/base/ContentFrameMessageManager.h b/dom/base/ContentFrameMessageManager.h index d1d529a5a8e6..2591e78cb064 100644 --- a/dom/base/ContentFrameMessageManager.h +++ b/dom/base/ContentFrameMessageManager.h @@ -15,6 +15,10 @@ namespace mozilla { namespace dom { +template +struct Nullable; +class WindowProxyHolder; + #define NS_CONTENTFRAMEMESSAGEMANAGER_IID \ { \ 0x97e192a6, 0xab7a, 0x4c8f, { \ @@ -33,8 +37,7 @@ class ContentFrameMessageManager : public DOMEventTargetHelper, NS_DECLARE_STATIC_IID_ACCESSOR(NS_CONTENTFRAMEMESSAGEMANAGER_IID) - virtual already_AddRefed GetContent( - ErrorResult& aError) = 0; + virtual Nullable GetContent(ErrorResult& aError) = 0; virtual already_AddRefed GetDocShell(ErrorResult& aError) = 0; virtual already_AddRefed GetTabEventTarget() = 0; virtual uint64_t ChromeOuterWindowID() = 0; diff --git a/dom/base/InProcessTabChildMessageManager.cpp b/dom/base/InProcessTabChildMessageManager.cpp index a9ef37bf1666..ef7bff5637d9 100644 --- a/dom/base/InProcessTabChildMessageManager.cpp +++ b/dom/base/InProcessTabChildMessageManager.cpp @@ -19,6 +19,7 @@ #include "mozilla/dom/MessageManagerBinding.h" #include "mozilla/dom/SameProcessMessageQueue.h" #include "mozilla/dom/ScriptLoader.h" +#include "mozilla/dom/WindowProxyHolder.h" using namespace mozilla; using namespace mozilla::dom; @@ -147,13 +148,16 @@ void InProcessTabChildMessageManager::CacheFrameLoader( mFrameLoader = aFrameLoader; } -already_AddRefed -InProcessTabChildMessageManager::GetContent(ErrorResult& aError) { +Nullable InProcessTabChildMessageManager::GetContent( + ErrorResult& aError) { nsCOMPtr content; if (mDocShell) { content = mDocShell->GetWindow(); } - return content.forget(); + if (!content) { + return nullptr; + } + return WindowProxyHolder(content); } already_AddRefed diff --git a/dom/base/InProcessTabChildMessageManager.h b/dom/base/InProcessTabChildMessageManager.h index 3c9c74d68c0b..9175b3092a34 100644 --- a/dom/base/InProcessTabChildMessageManager.h +++ b/dom/base/InProcessTabChildMessageManager.h @@ -65,8 +65,7 @@ class InProcessTabChildMessageManager final virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - virtual already_AddRefed GetContent( - ErrorResult& aError) override; + Nullable GetContent(ErrorResult& aError) override; virtual already_AddRefed GetDocShell( ErrorResult& aError) override { nsCOMPtr docShell(mDocShell); diff --git a/dom/base/WindowProxyHolder.h b/dom/base/WindowProxyHolder.h new file mode 100644 index 000000000000..dee00fc4183c --- /dev/null +++ b/dom/base/WindowProxyHolder.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 mozilla_dom_WindowProxyHolder_h__ +#define mozilla_dom_WindowProxyHolder_h__ + +#include "nsPIDOMWindow.h" + +namespace mozilla { +namespace dom { + +/** + * This class is used for passing arguments and the return value for WebIDL + * binding code that takes/returns a WindowProxy object and for WebIDL + * unions/dictionaries that contain a WindowProxy member. It should never + * contain null; if the value in WebIDL is nullable the binding code will use a + * Nullable. + */ +class WindowProxyHolder { + public: + WindowProxyHolder() = default; + explicit WindowProxyHolder(nsPIDOMWindowOuter* aWin) : mWindow(aWin) { + MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null."); + } + explicit WindowProxyHolder(already_AddRefed&& aWin) + : mWindow(std::move(aWin)) { + MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null."); + } + WindowProxyHolder& operator=(nsPIDOMWindowOuter* aWin) { + mWindow = aWin; + MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null."); + return *this; + } + WindowProxyHolder& operator=(already_AddRefed&& aWin) { + mWindow = std::move(aWin); + MOZ_ASSERT(mWindow, "Don't set WindowProxyHolder to null."); + return *this; + } + + nsPIDOMWindowOuter* get() const { + MOZ_ASSERT(mWindow, "WindowProxyHolder hasn't been initialized."); + return mWindow; + } + + private: + friend void ImplCycleCollectionUnlink(WindowProxyHolder& aProxy); + + nsCOMPtr mWindow; +}; + +inline void ImplCycleCollectionTraverse( + nsCycleCollectionTraversalCallback& aCallback, WindowProxyHolder& aProxy, + const char* aName, uint32_t aFlags = 0) { + CycleCollectionNoteChild(aCallback, aProxy.get(), "mWindow", aFlags); +} + +inline void ImplCycleCollectionUnlink(WindowProxyHolder& aProxy) { + aProxy.mWindow = nullptr; +} + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_WindowProxyHolder_h__ */ diff --git a/dom/base/moz.build b/dom/base/moz.build index 70df15720190..24221b84c57b 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -235,6 +235,7 @@ EXPORTS.mozilla.dom += [ 'VisualViewport.h', 'WebKitCSSMatrix.h', 'WindowOrientationObserver.h', + 'WindowProxyHolder.h', ] if CONFIG['FUZZING']: diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 7becb4b62a35..d19b9f55a3cf 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -294,6 +294,7 @@ #include "mozilla/net/ChannelEventQueue.h" #include "mozilla/net/RequestContextService.h" #include "StorageAccessPermissionRequest.h" +#include "mozilla/dom/WindowProxyHolder.h" #define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0) #define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1) @@ -3366,6 +3367,14 @@ nsresult nsIDocument::GetSrcdocData(nsAString& aSrcdocData) { return NS_OK; } +Nullable nsIDocument::GetDefaultView() const { + nsPIDOMWindowOuter* win = GetWindow(); + if (!win) { + return nullptr; + } + return WindowProxyHolder(win); +} + Element* nsIDocument::GetActiveElement() { // Get the focused element. Element* focusedElement = GetRetargetedFocusedElement(); diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp index d6cf2971f1b0..327806412f80 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -2546,7 +2546,7 @@ bool nsGlobalWindowInner::HasActiveSpeechSynthesis() { #endif -already_AddRefed nsGlobalWindowInner::GetParent( +Nullable nsGlobalWindowInner::GetParent( ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetParentOuter, (), aError, nullptr); } @@ -3306,7 +3306,7 @@ double nsGlobalWindowInner::GetScrollY(ErrorResult& aError) { uint32_t nsGlobalWindowInner::Length() { FORWARD_TO_OUTER(Length, (), 0); } -already_AddRefed nsGlobalWindowInner::GetTop( +Nullable nsGlobalWindowInner::GetTop( mozilla::ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetTopOuter, (), aError, nullptr); } @@ -3684,14 +3684,15 @@ void nsGlobalWindowInner::ReleaseEvents() { } } -already_AddRefed nsGlobalWindowInner::Open( - const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions, - ErrorResult& aError) { +Nullable nsGlobalWindowInner::Open(const nsAString& aUrl, + const nsAString& aName, + const nsAString& aOptions, + ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(OpenOuter, (aUrl, aName, aOptions, aError), aError, nullptr); } -already_AddRefed nsGlobalWindowInner::OpenDialog( +Nullable nsGlobalWindowInner::OpenDialog( JSContext* aCx, const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions, const Sequence& aExtraArgument, ErrorResult& aError) { @@ -3881,7 +3882,7 @@ void nsGlobalWindowInner::Btoa(const nsAString& aBinaryData, // EventTarget //***************************************************************************** -nsPIDOMWindowOuter* nsGlobalWindowInner::GetOwnerGlobalForBindings() { +nsPIDOMWindowOuter* nsGlobalWindowInner::GetOwnerGlobalForBindingsInternal() { return nsPIDOMWindowOuter::GetFromCurrentInner(this); } diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h index 1d09baa2101f..c19322a309cd 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h @@ -306,7 +306,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final; - virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override; + virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override; virtual nsIGlobalObject* GetOwnerGlobal() const override; @@ -623,7 +623,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, nsDOMWindowList* GetFrames() final; already_AddRefed GetFrames(mozilla::ErrorResult& aError); uint32_t Length(); - already_AddRefed GetTop(mozilla::ErrorResult& aError); + mozilla::dom::Nullable GetTop( + mozilla::ErrorResult& aError); protected: explicit nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow); @@ -637,15 +638,15 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, void SetOpener(JSContext* aCx, JS::Handle aOpener, mozilla::ErrorResult& aError); void GetEvent(JSContext* aCx, JS::MutableHandle aRetval); - already_AddRefed GetParent(mozilla::ErrorResult& aError); + mozilla::dom::Nullable GetParent( + mozilla::ErrorResult& aError); nsPIDOMWindowOuter* GetScriptableParent() override; mozilla::dom::Element* GetFrameElement(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError); mozilla::dom::Element* GetFrameElement() override; - already_AddRefed Open(const nsAString& aUrl, - const nsAString& aName, - const nsAString& aOptions, - mozilla::ErrorResult& aError); + mozilla::dom::Nullable Open( + const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions, + mozilla::ErrorResult& aError); nsDOMOfflineResourceList* GetApplicationCache(mozilla::ErrorResult& aError); nsDOMOfflineResourceList* GetApplicationCache() override; @@ -857,7 +858,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, bool ShouldResistFingerprinting(); - already_AddRefed OpenDialog( + mozilla::dom::Nullable OpenDialog( JSContext* aCx, const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions, const mozilla::dom::Sequence& aExtraArgument, diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index 458de55cb0b6..7c89ce13c0ab 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -38,6 +38,7 @@ #include "mozilla/dom/Timeout.h" #include "mozilla/dom/TimeoutHandler.h" #include "mozilla/dom/TimeoutManager.h" +#include "mozilla/dom/WindowProxyHolder.h" #include "mozilla/IntegerPrintfMacros.h" #if defined(MOZ_WIDGET_ANDROID) #include "mozilla/dom/WindowOrientationObserver.h" @@ -2624,19 +2625,13 @@ bool nsPIDOMWindowOuter::GetServiceWorkersTestingEnabled() { return topWindow->mServiceWorkersTestingEnabled; } -already_AddRefed nsGlobalWindowOuter::GetParentOuter() { - if (!mDocShell) { +Nullable nsGlobalWindowOuter::GetParentOuter() { + nsPIDOMWindowOuter* parent = GetScriptableParent(); + if (!parent) { return nullptr; } - nsCOMPtr parent; - if (mDocShell->GetIsMozBrowser()) { - parent = this; - } else { - parent = GetParent(); - } - - return parent.forget(); + return WindowProxyHolder(parent); } /** @@ -2647,8 +2642,16 @@ already_AddRefed nsGlobalWindowOuter::GetParentOuter() { * mozbrowser>, we will return |this| as its own parent. */ nsPIDOMWindowOuter* nsGlobalWindowOuter::GetScriptableParent() { - nsCOMPtr parent = GetParentOuter(); - return parent.get(); + if (!mDocShell) { + return nullptr; + } + + if (mDocShell->GetIsMozBrowser()) { + return this; + } + + nsCOMPtr parent = GetParent(); + return parent; } /** @@ -2769,7 +2772,8 @@ already_AddRefed nsGlobalWindowOuter::GetContentInternal( // If we're contained in