diff --git a/browser/base/content/pageinfo/pageInfo.js b/browser/base/content/pageinfo/pageInfo.js index 3959278f3072..f31246e1ded1 100644 --- a/browser/base/content/pageinfo/pageInfo.js +++ b/browser/base/content/pageinfo/pageInfo.js @@ -149,7 +149,10 @@ pageInfoTreeView.prototype = { return 0; }, getImageSrc(row, column) {}, - getCellValue(row, column) {}, + getCellValue(row, column) { + let col = column != null ? column : this.copycol; + return row < 0 || col < 0 ? "" : this.data[row][col] || ""; + }, toggleOpenState(index) {}, cycleHeader(col) {}, selectionChanged() {}, @@ -269,6 +272,19 @@ const nsIPermissionManager = Ci.nsIPermissionManager; const nsICertificateDialogs = Ci.nsICertificateDialogs; const CERTIFICATEDIALOGS_CONTRACTID = "@mozilla.org/nsCertificateDialogs;1"; +// clipboard helper +function getClipboardHelper() { + try { + return Cc["@mozilla.org/widget/clipboardhelper;1"].getService( + Ci.nsIClipboardHelper + ); + } catch (e) { + // do nothing, later code will handle the error + return null; + } +} +const gClipboardHelper = getClipboardHelper(); + // namespaces, don't need all of these yet... const XLinkNS = "http://www.w3.org/1999/xlink"; const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; @@ -1175,6 +1191,37 @@ function formatDate(datestr, unknown) { return dateTimeFormatter.format(date); } +function doCopy() { + if (!gClipboardHelper) { + return; + } + + var elem = document.commandDispatcher.focusedElement; + + if (elem && elem.localName == "tree") { + var view = elem.view; + var selection = view.selection; + var text = [], + tmp = ""; + var min = {}, + max = {}; + + var count = selection.getRangeCount(); + + for (var i = 0; i < count; i++) { + selection.getRangeAt(i, min, max); + + for (var row = min.value; row <= max.value; row++) { + tmp = view.getCellValue(row, null); + if (tmp) { + text.push(tmp); + } + } + } + gClipboardHelper.copyString(text.join("\n")); + } +} + function doSelectAllMedia() { var tree = document.getElementById("imagetree"); diff --git a/browser/base/content/pageinfo/pageInfo.xul b/browser/base/content/pageinfo/pageInfo.xul index 3f703915d92e..b627afd527f8 100644 --- a/browser/base/content/pageinfo/pageInfo.xul +++ b/browser/base/content/pageinfo/pageInfo.xul @@ -47,6 +47,7 @@ + @@ -58,12 +59,14 @@ #else #endif + + diff --git a/browser/base/content/test/permissions/browser_temporary_permissions.js b/browser/base/content/test/permissions/browser_temporary_permissions.js index bbc9c026ac59..66d09a79df8b 100644 --- a/browser/base/content/test/permissions/browser_temporary_permissions.js +++ b/browser/base/content/test/permissions/browser_temporary_permissions.js @@ -72,7 +72,7 @@ add_task(async function testTempPermissionSubframes() { // FIXME(Fission): The load event fires before cross-origin iframes have // loaded (bug 1559841). if (content.SpecialPowers.useRemoteSubframes) { - for (let i = 0; i < 200; i++) { + for (let i = 0; i < 800; i++) { await new Promise(resolve => content.setTimeout(resolve, 0)); } } diff --git a/browser/locales/en-US/browser/pageInfo.ftl b/browser/locales/en-US/browser/pageInfo.ftl index 33256ef1d338..c45dc3c3b51a 100644 --- a/browser/locales/en-US/browser/pageInfo.ftl +++ b/browser/locales/en-US/browser/pageInfo.ftl @@ -5,6 +5,12 @@ page-info-window = .style = width: 600px; min-height: 550px; +copy = + .key = C +menu-copy = + .label = Copy + .accesskey = C + select-all = .key = A menu-select-all = diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp index 3cdb775f6d9a..0e211f459be0 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp @@ -132,7 +132,10 @@ already_AddRefed BrowsingContext::Create( // The name and opener fields need to be explicitly initialized. Don't bother // using transactions to set them, as we haven't been attached yet. context->mName = aName; - context->mOpenerId = aOpener ? aOpener->Id() : 0; + if (aOpener) { + context->mOpenerId = aOpener->Id(); + context->mHadOriginalOpener = true; + } context->mEmbedderPolicy = nsILoadInfo::EMBEDDER_POLICY_NULL; BrowsingContext* inherit = aParent ? aParent : aOpener; diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h index 8dc103373d40..67a796548116 100644 --- a/docshell/base/BrowsingContext.h +++ b/docshell/base/BrowsingContext.h @@ -209,13 +209,22 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase { BrowsingContext* Top(); - already_AddRefed GetOpener() const { return Get(mOpenerId); } + already_AddRefed GetOpener() const { + RefPtr opener(Get(mOpenerId)); + if (!mIsDiscarded && opener && !opener->mIsDiscarded) { + return opener.forget(); + } + return nullptr; + } void SetOpener(BrowsingContext* aOpener) { + MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->Group() == Group()); SetOpenerId(aOpener ? aOpener->Id() : 0); } bool HasOpener() const; + bool HadOriginalOpener() const { return mHadOriginalOpener; } + /** * When a new browsing context is opened by a sandboxed document, it needs to * keep track of the browsing context that opened it, so that it can be @@ -481,9 +490,7 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase { uintptr_t(this) - offsetof(BrowsingContext, mLocation)); } - already_AddRefed GetDocShell() override { - return nullptr; - } + already_AddRefed GetDocShell() override { return nullptr; } }; // Ensure that opener is in the same BrowsingContextGroup. diff --git a/docshell/base/BrowsingContextFieldList.h b/docshell/base/BrowsingContextFieldList.h index 15c1e9c8e21d..8b522aad7c07 100644 --- a/docshell/base/BrowsingContextFieldList.h +++ b/docshell/base/BrowsingContextFieldList.h @@ -21,6 +21,8 @@ MOZ_BC_FIELD(OpenerId, uint64_t) MOZ_BC_FIELD(OnePermittedSandboxedNavigatorId, uint64_t) +MOZ_BC_FIELD(HadOriginalOpener, bool) + // Toplevel browsing contexts only. This field controls whether the browsing // context is currently considered to be activated by a gesture. MOZ_BC_FIELD(IsActivatedByUserGesture, bool) diff --git a/docshell/base/nsDSURIContentListener.cpp b/docshell/base/nsDSURIContentListener.cpp index c46da4f57e68..a5b0ddfa7990 100644 --- a/docshell/base/nsDSURIContentListener.cpp +++ b/docshell/base/nsDSURIContentListener.cpp @@ -16,6 +16,7 @@ #include "nsError.h" #include "nsContentSecurityManager.h" #include "nsDocShellLoadTypes.h" +#include "nsGlobalWindowOuter.h" #include "nsIInterfaceRequestor.h" #include "nsIMultiPartChannel.h" @@ -48,10 +49,11 @@ nsIInterfaceRequestor* MaybeCloseWindowHelper::MaybeCloseWindow() { if (mShouldCloseWindow) { // Reset the window context to the opener window so that the dependent // dialogs have a parent - nsCOMPtr opener = window->GetOpener(); + nsCOMPtr opener = + nsGlobalWindowOuter::Cast(window)->GetSameProcessOpener(); if (opener && !opener->Closed()) { - mContentContext = do_GetInterface(opener); + mContentContext = do_QueryInterface(opener); // Now close the old window. Do it on a timer so that we don't run // into issues trying to close the window before it has fully opened. diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 90b219210e00..d34acc6a15ad 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -14863,12 +14863,12 @@ void Document::MaybeAllowStorageForOpenerAfterUserInteraction() { return; } - nsCOMPtr outer = inner->GetOuterWindow(); + auto* outer = nsGlobalWindowOuter::Cast(inner->GetOuterWindow()); if (NS_WARN_IF(!outer)) { return; } - nsCOMPtr outerOpener = outer->GetOpener(); + nsCOMPtr outerOpener = outer->GetSameProcessOpener(); if (!outerOpener) { return; } diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index e0687c7089d2..decf687055a9 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -2084,12 +2084,6 @@ nsresult nsFrameLoader::MaybeCreateDocShell() { newWindow->SetFrameElementInternal(mOwnerContent); - // TODO(farre): Remove this when nsGlobalWindowOuter::GetOpenerWindowOuter - // starts using BrowsingContext::GetOpener. - if (RefPtr opener = mBrowsingContext->GetOpener()) { - newWindow->SetOpenerWindow(opener->GetDOMWindow(), true); - } - // Allow scripts to close the docshell if specified. if (mOwnerContent->IsXULElement(nsGkAtoms::browser) && mOwnerContent->AttrValueIs(kNameSpaceID_None, diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp index a13a455d78c4..65c7dbcc4e10 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -3034,27 +3034,33 @@ nsresult nsGlobalWindowInner::GetControllers(nsIControllers** aResult) { return rv.StealNSResult(); } -nsPIDOMWindowOuter* nsGlobalWindowInner::GetOpenerWindow(ErrorResult& aError) { +Nullable nsGlobalWindowInner::GetOpenerWindow( + ErrorResult& aError) { FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr); } void nsGlobalWindowInner::GetOpener(JSContext* aCx, JS::MutableHandle aRetval, ErrorResult& aError) { - nsCOMPtr opener = GetOpenerWindow(aError); - if (aError.Failed() || !opener) { + Nullable opener = GetOpenerWindow(aError); + if (aError.Failed() || opener.IsNull()) { aRetval.setNull(); return; } - aError = nsContentUtils::WrapNative(aCx, opener, aRetval); + if (!ToJSValue(aCx, opener.Value(), aRetval)) { + aError.NoteJSContextException(aCx); + } } void nsGlobalWindowInner::SetOpener(JSContext* aCx, JS::Handle aOpener, ErrorResult& aError) { if (aOpener.isNull()) { - FORWARD_TO_OUTER_VOID(SetOpenerWindow, (nullptr, false)); + RefPtr bc(GetBrowsingContext()); + if (!bc->IsDiscarded()) { + bc->SetOpener(nullptr); + } return; } diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h index 32029b6f3597..f35c31ba55db 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h @@ -622,7 +622,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, void InitWasOffline(); public: - nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError); + mozilla::dom::Nullable GetOpenerWindow( + mozilla::ErrorResult& aError); void GetOpener(JSContext* aCx, JS::MutableHandle aRetval, mozilla::ErrorResult& aError); void SetOpener(JSContext* aCx, JS::Handle aOpener, diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index ff5274f71d35..8735e91149d5 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -1095,7 +1095,6 @@ nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID) mIsClosed(false), mInClose(false), mHavePendingClose(false), - mHadOriginalOpener(false), mIsPopupSpam(false), mBlockScriptedClosingFlag(false), mWasOffline(false), @@ -1298,10 +1297,7 @@ void nsGlobalWindowOuter::CleanUp() { ClearControllers(); - mOpener = nullptr; // Forces Release - if (mContext) { - mContext = nullptr; // Forces Release - } + mContext = nullptr; // Forces Release mChromeEventHandler = nullptr; // Forces Release mParentTarget = nullptr; mMessageManager = nullptr; @@ -2518,70 +2514,6 @@ void nsGlobalWindowOuter::DetachFromDocShell() { CleanUp(); } -void nsGlobalWindowOuter::SetOpenerWindow(nsPIDOMWindowOuter* aOpener, - bool aOriginalOpener) { - nsWeakPtr opener = do_GetWeakReference(aOpener); - if (opener == mOpener) { - MOZ_DIAGNOSTIC_ASSERT(!aOpener || !aOpener->GetDocShell() || - (GetBrowsingContext() && - aOpener->GetBrowsingContext() && - aOpener->GetBrowsingContext()->Id() == - GetBrowsingContext()->GetOpenerId())); - return; - } - - NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled, - "aOriginalOpener is true, but not first call to " - "SetOpenerWindow!"); - NS_ASSERTION(aOpener || !aOriginalOpener, - "Shouldn't set mHadOriginalOpener if aOpener is null"); - - mOpener = opener.forget(); - NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!"); - - if (mDocShell) { - MOZ_DIAGNOSTIC_ASSERT( - !aOriginalOpener || !aOpener || - // TODO(farre): Allowing to set a closed or closing window as - // opener is not ideal, since it won't have a docshell and - // therefore no browsing context. This means that we're - // effectively setting the browsing context opener to null and - // the window opener to a closed window. This needs to be - // cleaned up, see Bug 1511353. - nsGlobalWindowOuter::Cast(aOpener)->IsClosedOrClosing() || - // TODO(farre): Allowing to set an opener on a closed window is - // not ideal either, but we need to allow it for now. Bug 1543056. - IsClosedOrClosing() || - aOpener->GetBrowsingContext()->Id() == - GetBrowsingContext()->GetOpenerId()); - // TODO(farre): Here we really wish to only consider the case - // where 'aOriginalOpener'. See bug 1509016. - GetBrowsingContext()->SetOpener(aOpener ? aOpener->GetBrowsingContext() - : nullptr); - } - - // Check that the js visible opener matches! We currently don't depend on this - // being true outside of nightly, so we disable the assertion in optimized - // release / beta builds. - nsPIDOMWindowOuter* contentOpener = GetSanitizedOpener(aOpener); - - // contentOpener is not used when the DIAGNOSTIC_ASSERT is compiled out. - mozilla::Unused << contentOpener; - MOZ_DIAGNOSTIC_ASSERT( - !contentOpener || !mTabGroup || - mTabGroup == nsGlobalWindowOuter::Cast(contentOpener)->mTabGroup); - - if (aOriginalOpener) { - MOZ_ASSERT(!mHadOriginalOpener, - "Probably too late to call ComputeIsSecureContext again"); - mHadOriginalOpener = true; - } - -#ifdef DEBUG - mSetOpenerWindowCalled = true; -#endif -} - void nsGlobalWindowOuter::UpdateParentTarget() { // NOTE: This method is nearly identical to // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD, @@ -3290,63 +3222,44 @@ nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) { FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED); } -nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSanitizedOpener( - nsPIDOMWindowOuter* aOpener) { - if (!aOpener) { +already_AddRefed +nsGlobalWindowOuter::GetOpenerBrowsingContext() { + RefPtr opener = GetBrowsingContext()->GetOpener(); + MOZ_DIAGNOSTIC_ASSERT(!opener || + opener->Group() == GetBrowsingContext()->Group()); + if (!opener || opener->Group() != GetBrowsingContext()->Group()) { return nullptr; } - nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(aOpener); - - // First, ensure that we're not handing back a chrome window to content: - if (win->IsChromeWindow()) { - return nullptr; - } - - // We don't want to reveal the opener if the opener is a mail window, - // because opener can be used to spoof the contents of a message (bug 105050). - // So, we look in the opener's root docshell to see if it's a mail window. - nsCOMPtr openerDocShell = aOpener->GetDocShell(); - - if (openerDocShell) { - nsCOMPtr openerRootItem; - openerDocShell->GetInProcessRootTreeItem(getter_AddRefs(openerRootItem)); - nsCOMPtr openerRootDocShell(do_QueryInterface(openerRootItem)); - if (openerRootDocShell) { - nsIDocShell::AppType appType = openerRootDocShell->GetAppType(); - if (appType != nsIDocShell::APP_TYPE_MAIL) { - return aOpener; - } + // Catch the case where we're chrome but the opener is not... + if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() && + GetPrincipal() == nsContentUtils::GetSystemPrincipal()) { + auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow()); + if (!openerWin || + openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) { + return nullptr; } } + return opener.forget(); +} + +nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() { + if (RefPtr opener = GetOpenerBrowsingContext()) { + return opener->GetDOMWindow(); + } return nullptr; } -nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOpenerWindowOuter() { - nsCOMPtr opener = do_QueryReferent(mOpener); - - if (!opener) { - return nullptr; +Nullable nsGlobalWindowOuter::GetOpenerWindowOuter() { + if (RefPtr opener = GetOpenerBrowsingContext()) { + return WindowProxyHolder(opener.forget()); } - - // First, check if we were called from a privileged chrome script - if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { - // Catch the case where we're chrome but the opener is not... - if (GetPrincipal() == nsContentUtils::GetSystemPrincipal() && - nsGlobalWindowOuter::Cast(opener)->GetPrincipal() != - nsContentUtils::GetSystemPrincipal()) { - return nullptr; - } - return opener; - } - - return GetSanitizedOpener(opener); + return nullptr; } -already_AddRefed nsGlobalWindowOuter::GetOpener() { - nsCOMPtr opener = GetOpenerWindowOuter(); - return opener.forget(); +Nullable nsGlobalWindowOuter::GetOpener() { + return GetOpenerWindowOuter(); } void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) { @@ -4740,7 +4653,7 @@ bool nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType) { if (aCallerType != CallerType::System) { // Don't allow scripts to move or resize windows that were not opened by a // script. - if (!mHadOriginalOpener) { + if (!HadOriginalOpener()) { return false; } @@ -4972,13 +4885,15 @@ void nsGlobalWindowOuter::FocusOuter() { nsCOMPtr caller = do_QueryInterface(GetEntryGlobal()); nsPIDOMWindowOuter* callerOuter = caller ? caller->GetOuterWindow() : nullptr; - nsCOMPtr opener = GetOpener(); + BrowsingContext* callerBC = + callerOuter ? callerOuter->GetBrowsingContext() : nullptr; + RefPtr openerBC = GetOpenerBrowsingContext(); // Enforce dom.disable_window_flip (for non-chrome), but still allow the // window which opened us to raise us at times when popups are allowed // (bugs 355482 and 369306). bool canFocus = CanSetProperty("dom.disable_window_flip") || - (opener == callerOuter && + (openerBC == callerBC && RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) < PopupBlocker::openBlocked); @@ -6283,7 +6198,7 @@ void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) { NS_ENSURE_SUCCESS_VOID(rv); if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) && - !mHadOriginalOpener && !aTrustedCaller) { + !HadOriginalOpener() && !aTrustedCaller) { bool allowClose = mAllowScriptsToClose || Preferences::GetBool("dom.allow_scripts_to_close_windows", true); @@ -7781,11 +7696,11 @@ mozilla::dom::TabGroup* nsGlobalWindowOuter::TabGroupOuter() { // because a document is getting its NodePrincipal, and asking for the // TabGroup to determine its DocGroup. if (!mTabGroup) { - // Get mOpener ourselves, instead of relying on GetOpenerWindowOuter, + // Get the opener ourselves, instead of relying on GetOpenerWindowOuter, // because that way we dodge the LegacyIsCallerChromeOrNativeCode() call // which we want to return false. - nsCOMPtr piOpener = do_QueryReferent(mOpener); - nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener); + RefPtr openerBC = GetBrowsingContext()->GetOpener(); + nsPIDOMWindowOuter* opener = openerBC ? openerBC->GetDOMWindow() : nullptr; nsPIDOMWindowOuter* parent = GetInProcessScriptableParentOrNull(); MOZ_ASSERT(!parent || !opener, "Only one of parent and opener may be provided"); @@ -7823,9 +7738,11 @@ mozilla::dom::TabGroup* nsGlobalWindowOuter::TabGroupOuter() { // Sanity check that our tabgroup matches our opener or parent. RefPtr parent = GetInProcessScriptableParentOrNull(); MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup); - nsCOMPtr piOpener = do_QueryReferent(mOpener); - nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener); - MOZ_ASSERT_IF(opener && nsGlobalWindowOuter::Cast(opener) != this, + + RefPtr openerBC = GetBrowsingContext()->GetOpener(); + nsPIDOMWindowOuter* opener = + openerBC ? openerBC->GetDOMWindow() : nullptr; + MOZ_ASSERT_IF(opener && Cast(opener) != this, opener->TabGroup() == mTabGroup); } mIsValidatingTabGroup = false; diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h index 4aa373e05b43..5a3add271c6e 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h @@ -323,9 +323,6 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, // Outer windows only. void DispatchDOMWindowCreated(); - virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener, - bool aOriginalOpener) override; - // Outer windows only. virtual void EnsureSizeAndPositionUpToDate() override; @@ -456,7 +453,9 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, bool IsCleanedUp() const { return mCleanedUp; } - bool HadOriginalOpener() const { return mHadOriginalOpener; } + bool HadOriginalOpener() const { + return GetBrowsingContext()->HadOriginalOpener(); + } bool IsTopLevelWindow(); @@ -548,14 +547,15 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, RefPtr mPostMessageEventQueue; protected: - nsPIDOMWindowOuter* GetOpenerWindowOuter(); + mozilla::dom::Nullable + GetOpenerWindowOuter(); // Initializes the mWasOffline member variable void InitWasOffline(); public: - nsPIDOMWindowOuter* GetSanitizedOpener(nsPIDOMWindowOuter* aOpener); - - already_AddRefed GetOpener() override; + nsPIDOMWindowOuter* GetSameProcessOpener(); + already_AddRefed GetOpenerBrowsingContext(); + mozilla::dom::Nullable GetOpener() override; mozilla::dom::Nullable GetParentOuter(); already_AddRefed GetInProcessParent() override; nsPIDOMWindowOuter* GetInProcessScriptableParent() override; @@ -1074,7 +1074,6 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, // close us when the JS stops executing or that we have a close // event posted. If this is set, just ignore window.close() calls. bool mHavePendingClose : 1; - bool mHadOriginalOpener : 1; bool mIsPopupSpam : 1; // Indicates whether scripts are allowed to close this window. @@ -1100,7 +1099,6 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, bool mHasStorageAccess : 1; nsCOMPtr mContext; - nsWeakPtr mOpener; nsCOMPtr mControllers; // For |window.arguments|, via |openDialog|. diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 25516939d09d..251aca82b294 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -885,16 +885,6 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy { Document* aDocument, nsISupports* aState, bool aForceReuseInnerWindow, mozilla::dom::WindowGlobalChild* aActor = nullptr) = 0; - /** - * Set the opener window. aOriginalOpener is true if and only if this is the - * original opener for the window. That is, it can only be true at most once - * during the life cycle of a window, and then only the first time - * SetOpenerWindow is called. It might never be true, of course, if the - * window does not have an opener when it's created. - */ - virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener, - bool aOriginalOpener) = 0; - /** * Ensure the size and position of this window are up-to-date by doing * a layout flush in the parent (which will in turn, do a layout flush @@ -1047,7 +1037,8 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy { virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0; virtual nsresult GetControllers(nsIControllers** aControllers) = 0; virtual already_AddRefed GetSelection() = 0; - virtual already_AddRefed GetOpener() = 0; + virtual mozilla::dom::Nullable + GetOpener() = 0; // aLoadState will be passed on through to the windowwatcher. // aForceNoOpener will act just like a "noopener" feature in aOptions except diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 6045dbe3fcf9..364db76ba4ba 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -962,16 +962,17 @@ nsresult ContentChild::ProvideWindowCommon( // parent. Otherwise, the parent could send messages to us before we have a // proper TabGroup for that actor. RefPtr tabGroup; + RefPtr openerBC; if (aTabOpener && !aForceNoOpener) { // The new actor will use the same tab group as the opener. tabGroup = aTabOpener->TabGroup(); + if (aParent) { + openerBC = nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext(); + } } else { tabGroup = new TabGroup(); } - RefPtr openerBC = - aParent ? nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext() - : nullptr; RefPtr browsingContext = BrowsingContext::Create( nullptr, openerBC, aName, BrowsingContext::Type::Content); @@ -1099,17 +1100,25 @@ nsresult ContentChild::ProvideWindowCommon( newChild->SetMaxTouchPoints(maxTouchPoints); newChild->SetHasSiblings(hasSiblings); - // Set the opener window for this window before we start loading the - // document inside of it. We have to do this before loading the remote - // scripts, because they can poke at the document and cause the Document - // to be created before the openerwindow - nsCOMPtr windowProxy = - do_GetInterface(newChild->WebNavigation()); - if (!aForceNoOpener && windowProxy && aParent) { - nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::From(windowProxy); - nsPIDOMWindowOuter* parent = nsPIDOMWindowOuter::From(aParent); - outer->SetOpenerWindow(parent, *aWindowIsNew); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + if (nsCOMPtr outer = + do_GetInterface(newChild->WebNavigation())) { + BrowsingContext* bc = outer->GetBrowsingContext(); + auto parentBC = + aParent + ? nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext()->Id() + : 0; + + if (aForceNoOpener) { + MOZ_DIAGNOSTIC_ASSERT(!*aWindowIsNew || !bc->HadOriginalOpener()); + MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == 0); + } else { + MOZ_DIAGNOSTIC_ASSERT(!*aWindowIsNew || + bc->HadOriginalOpener() == !!parentBC); + MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == parentBC); + } } +#endif // Unfortunately we don't get a window unless we've shown the frame. That's // pretty bogus; see bug 763602. diff --git a/dom/tests/mochitest/bugs/mochitest.ini b/dom/tests/mochitest/bugs/mochitest.ini index 786558a97061..4dc5f9bc8ef6 100644 --- a/dom/tests/mochitest/bugs/mochitest.ini +++ b/dom/tests/mochitest/bugs/mochitest.ini @@ -38,6 +38,8 @@ support-files = test2_bug622361.html file1_bug414291.html file2_bug414291.html +prefs = + fission.rebuild_frameloaders_on_remoteness_change=true [test_DOMWindowCreated_chromeonly.html] [test_bug132255.html] diff --git a/dom/tests/mochitest/localstorage/mochitest.ini b/dom/tests/mochitest/localstorage/mochitest.ini index 1a5ea9589926..fb0850bb9467 100644 --- a/dom/tests/mochitest/localstorage/mochitest.ini +++ b/dom/tests/mochitest/localstorage/mochitest.ini @@ -18,6 +18,8 @@ support-files = frameLocalStorageSessionOnly.html file_tryAccessSessionStorage.html windowProxy.html +prefs = + fission.rebuild_frameloaders_on_remoteness_change=true [test_brokenUTF-16.html] [test_bug600307-DBOps.html] @@ -53,6 +55,5 @@ skip-if = toolkit == 'android' || (verify && (os == 'linux' || os == 'mac' || os [test_localStorageQuotaSessionOnly2.html] skip-if = true # bug 1347690 [test_localStorageReplace.html] -fail-if = fission skip-if = toolkit == 'android' [test_storageConstructor.html] diff --git a/dom/tests/mochitest/sessionstorage/mochitest.ini b/dom/tests/mochitest/sessionstorage/mochitest.ini index b129824718b6..33a9b1643f45 100644 --- a/dom/tests/mochitest/sessionstorage/mochitest.ini +++ b/dom/tests/mochitest/sessionstorage/mochitest.ini @@ -7,11 +7,12 @@ support-files = frameReplace.html interOriginSlave.js interOriginTest.js +prefs = + fission.rebuild_frameloaders_on_remoteness_change=true [test_sessionStorageBase.html] [test_sessionStorageBaseSessionOnly.html] [test_sessionStorageClone.html] -fail-if = fission skip-if = toolkit == 'android' [test_sessionStorageHttpHttps.html] skip-if = toolkit == 'android' #TIMED_OUT diff --git a/dom/tests/mochitest/whatwg/mochitest.ini b/dom/tests/mochitest/whatwg/mochitest.ini index bd7dfe998685..8eb1ef709873 100644 --- a/dom/tests/mochitest/whatwg/mochitest.ini +++ b/dom/tests/mochitest/whatwg/mochitest.ini @@ -15,6 +15,8 @@ support-files = postMessage_throw_helper.html postMessage_transfer_helper.html postMessage_userpass_helper.html +prefs = + fission.rebuild_frameloaders_on_remoteness_change=true [test_bug477323.html] [test_document_scripts.html] @@ -31,17 +33,14 @@ skip-if = fission # Timeouts [test_postMessage_joined.html] skip-if = fission # Timeouts [test_postMessage_onOther.html] -skip-if = fission #Bug 1571273 [test_postMessage_origin.xhtml] skip-if = fission # Timeouts [test_postMessage_override.html] skip-if = fission [test_postMessage_special.xhtml] [test_postMessage_structured_clone.html] -skip-if = fission #Bug 1570918 [test_postMessage_throw.html] [test_postMessage_transfer.html] -skip-if = fission #Bug 1571208 [test_postMessage_userpass.html] skip-if = fission # Timeouts [test_bug500328.html] diff --git a/dom/websocket/WebSocket.cpp b/dom/websocket/WebSocket.cpp index 490b1c8eb207..d0fd8e417ebb 100644 --- a/dom/websocket/WebSocket.cpp +++ b/dom/websocket/WebSocket.cpp @@ -2701,14 +2701,8 @@ nsresult WebSocketImpl::GetLoadingPrincipal(nsIPrincipal** aPrincipal) { // We are at the top. Let's see if we have an opener window. if (innerWindow == currentInnerWindow) { - ErrorResult error; - parentWindow = - nsGlobalWindowInner::Cast(innerWindow)->GetOpenerWindow(error); - if (NS_WARN_IF(error.Failed())) { - error.SuppressException(); - return NS_ERROR_DOM_SECURITY_ERR; - } - + parentWindow = nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow()) + ->GetSameProcessOpener(); if (!parentWindow) { break; } diff --git a/js/src/jit-test/tests/ctypes/conversion-to-number.js b/js/src/jit-test/tests/ctypes/conversion-to-number.js new file mode 100644 index 000000000000..6a334ecf3aeb --- /dev/null +++ b/js/src/jit-test/tests/ctypes/conversion-to-number.js @@ -0,0 +1,98 @@ +// Type conversion to number should use ECMA-style semantics. + +load(libdir + 'asserts.js'); + +function test() { + function checkValue(type, provided, expected) { + assertEq(ctypes[type](provided).value, expected, + `ctypes.${type}(${provided}) contains unexpected value`); + } + + function checkCantConvert(type, value) { + var ctor = ctypes[type]; + assertTypeErrorMessage(() => ctor(value), + /can't convert the number/); + } + + let testInt8 = checkValue.bind(undefined, "int8_t"); + let testInt8Throws = checkCantConvert.bind(undefined, "int8_t"); + testInt8(1e100, 0); + testInt8Throws(-129); + testInt8(-128, -128); + testInt8(-1, -1); + testInt8(0, 0); + testInt8(1, 1); + testInt8(127, 127); + testInt8Throws(128); + + let testUint8 = checkValue.bind(undefined, "uint8_t"); + let testUint8Throws = checkCantConvert.bind(undefined, "uint8_t"); + testUint8(1e100, 0); + testUint8Throws(-1); + testUint8(0, 0); + testUint8(1, 1); + testUint8(127, 127); + testUint8(128, 128); + testUint8(255, 255); + testUint8Throws(256); + + let testInt16 = checkValue.bind(undefined, "int16_t"); + let testInt16Throws = checkCantConvert.bind(undefined, "int16_t"); + testInt16(1e100, 0); + testInt16Throws(-32769); + testInt16(-32768, -32768); + testInt16(-1, -1); + testInt16(0, 0); + testInt16(1, 1); + testInt16(32767, 32767); + testInt16Throws(32768); + + let testUint16 = checkValue.bind(undefined, "uint16_t"); + let testUint16Throws = checkCantConvert.bind(undefined, "uint16_t"); + testUint16(1e100, 0); + testUint16Throws(-1); + testUint16(0, 0); + testUint16(1, 1); + testUint16(32767, 32767); + testUint16(32768, 32768); + testUint16(65535, 65535); + testUint16Throws(65536); + + let testInt32 = checkValue.bind(undefined, "int32_t"); + let testInt32Throws = checkCantConvert.bind(undefined, "int32_t"); + testInt32(1e100, 0); + // This probably should pass, but right now doubles fall into a different + // code path where no error occurs. ctypes is probably/hopefully declining in + // use now, so just don't bother with this test. + //testInt32Throws(-2147483649); + testInt32(-2147483648, -2147483648); + testInt32(-1, -1); + testInt32(0, 0); + testInt32(1, 1); + testInt32(2147483647, 2147483647); + // This probably should pass, but right now doubles fall into a different + // code path where no error occurs. ctypes is probably/hopefully declining in + // use now, so just don't bother with this test. + //testInt32Throws(2147483648); + + let testUint32 = checkValue.bind(undefined, "uint32_t"); + let testUint32Throws = checkCantConvert.bind(undefined, "uint32_t"); + testUint32(1e100, 0); + testUint32Throws(-1); + // This probably should pass, but right now doubles fall into a different + // code path where no error occurs. ctypes is probably/hopefully declining in + // use now, so just don't bother with this test. + //testUint32Throws(-1 * Math.cos(Math.PI)); // -1.0 encoded as a double + testUint32(0, 0); + testUint32(1, 1); + testUint32(2147483647, 2147483647); + testUint32(2147483648, 2147483648); + testUint32(4294967295, 4294967295); + // This probably should pass, but right now doubles fall into a different + // code path where no error occurs. ctypes is probably/hopefully declining in + // use now, so just don't bother with this test. + //testUint32Throws(4294967296); +} + +if (typeof ctypes === "object") + test(); diff --git a/toolkit/components/extensions/test/mochitest/mochitest-common.ini b/toolkit/components/extensions/test/mochitest/mochitest-common.ini index f991466a5161..b4d30d71e017 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini @@ -85,7 +85,6 @@ skip-if = (!debug && android_version == '18') #Bug 1523193 skip-if = os == 'android' # Android does not support multiple windows. [test_ext_contentscript_permission.html] [test_ext_cookies.html] -fail-if = fission [test_ext_cookies_containers.html] [test_ext_cookies_expiry.html] [test_ext_cookies_first_party.html] diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp index 2b9175b55e58..ed6fb81336d9 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp @@ -951,10 +951,19 @@ nsresult nsWindowWatcher::OpenWindowInternal( newDocShell->SetSandboxFlags(activeDocsSandboxFlags); } - nsCOMPtr win(newBC->GetDOMWindow()); + RefPtr win( + nsGlobalWindowOuter::Cast(newBC->GetDOMWindow())); if (win) { if (!aForceNoOpener) { - win->SetOpenerWindow(parentWindow, windowIsNew); + if (windowIsNew) { + // If this is a new window, its opener should have been set when its + // BrowsingContext was created. If not, we need to set it ourselves. + MOZ_DIAGNOSTIC_ASSERT(newBC->GetOpenerId() == + (parentBC ? parentBC->Id() : 0)); + MOZ_DIAGNOSTIC_ASSERT(!!parentBC == newBC->HadOriginalOpener()); + } else { + newBC->SetOpener(parentBC); + } } else if (parentWindow && parentWindow != win) { MOZ_ASSERT( win->TabGroup() != parentWindow->TabGroup(), @@ -1069,7 +1078,7 @@ nsresult nsWindowWatcher::OpenWindowInternal( // SetInitialPrincipalToSubject is safe to call multiple times. if (win) { nsCOMPtr cspToInheritForAboutBlank; - nsCOMPtr targetOpener = win->GetOpener(); + nsCOMPtr targetOpener = win->GetSameProcessOpener(); nsCOMPtr openerDocShell(do_GetInterface(targetOpener)); if (openerDocShell) { RefPtr openerDoc = @@ -1079,13 +1088,12 @@ nsresult nsWindowWatcher::OpenWindowInternal( win->SetInitialPrincipalToSubject(cspToInheritForAboutBlank); if (aIsPopupSpam) { - auto* globalWin = nsGlobalWindowOuter::Cast(win); - MOZ_ASSERT(!globalWin->IsPopupSpamWindow(), + MOZ_ASSERT(!win->IsPopupSpamWindow(), "Who marked it as popup spam already???"); - if (!globalWin->IsPopupSpamWindow()) { // Make sure we don't mess up - // our counter even if the above - // assert fails. - globalWin->SetIsPopupSpamWindow(true); + if (!win->IsPopupSpamWindow()) { // Make sure we don't mess up + // our counter even if the above + // assert fails. + win->SetIsPopupSpamWindow(true); } } } @@ -1162,7 +1170,8 @@ nsresult nsWindowWatcher::OpenWindowInternal( nsCOMPtr obsSvc = mozilla::services::GetObserverService(); if (obsSvc) { - obsSvc->NotifyObservers(win, "toplevel-window-ready", nullptr); + obsSvc->NotifyObservers(ToSupports(win), "toplevel-window-ready", + nullptr); } } diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp index 91c6589b7409..db17a3a84fea 100644 --- a/widget/gtk/WindowSurfaceWayland.cpp +++ b/widget/gtk/WindowSurfaceWayland.cpp @@ -189,7 +189,7 @@ It owns wl_buffer object, owns WaylandDMABufSurface (which provides the DMA Buffer) and ties them together. WindowBackBufferDMABuf backend is used only when WaylandDMABufSurface is -available and gfx.wayland_dmabuf_backend.enabled preference is set. +available and widget.wayland_dmabuf_backend.enabled preference is set. */ @@ -504,6 +504,8 @@ WindowSurfaceWayland::WindowSurfaceWayland(nsWindow* aWindow) mIsMainThread(NS_IsMainThread()), mNeedScaleFactorUpdate(true) { for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr; + mRenderingCacheMode = static_cast( + mWaylandDisplay->GetRenderingCacheModePref()); } WindowSurfaceWayland::~WindowSurfaceWayland() { @@ -810,10 +812,12 @@ already_AddRefed WindowSurfaceWayland::Lock( mBufferScreenRect = lockedScreenRect; } - if (mWholeWindowBufferDamage) { + if (mWholeWindowBufferDamage || mRenderingCacheMode != CACHE_ALL) { // We can lock/commit entire buffer direcly. mDrawToWaylandBufferDirectly = true; + } + if (mDrawToWaylandBufferDirectly) { // If there's any pending image commit scratch them as we're going // to redraw the whole sceen anyway. mDelayedImageCommits.Clear(); @@ -821,10 +825,29 @@ already_AddRefed WindowSurfaceWayland::Lock( RefPtr dt = LockWaylandBuffer( /* aCanSwitchBuffer */ mWholeWindowBufferDamage); if (dt) { + // TODO: Try to set clip regions according to given area provided by + // compositor, not sure it has any effect. Also disable when drawing + // without any cache to speed up rendering. + if (!mWholeWindowBufferDamage && mRenderingCacheMode != CACHE_NONE) { + uint32_t numRects = aRegion.GetNumRects(); + if (numRects != 1) { + AutoTArray rects; + rects.SetCapacity(numRects); + for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { + rects.AppendElement(iter.Get().ToUnknownRect()); + } + dt->PushDeviceSpaceClipRects(rects.Elements(), rects.Length()); + } + } return dt.forget(); } } + // Any caching is disabled and we don't have any back buffer available. + if (mRenderingCacheMode == CACHE_NONE) { + return nullptr; + } + // We do indirect drawing due to: // // 1) We don't have any front buffer available. Try indirect drawing diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h index a0c5f1889a62..cab054f93770 100644 --- a/widget/gtk/WindowSurfaceWayland.h +++ b/widget/gtk/WindowSurfaceWayland.h @@ -175,6 +175,21 @@ class WindowSurfaceWayland : public WindowSurface { void FrameCallbackHandler(); void DelayedCommitHandler(); + // Image cache mode can be set by widget.wayland_cache_mode + typedef enum { + // Cache and clip all drawings, default. It's slowest + // but also without any rendered artifacts. + CACHE_ALL = 0, + // Cache drawing only when back buffer is missing. May produce + // some rendering artifacts and flickering when partial screen update + // is rendered. + CACHE_MISSING = 1, + // Don't cache anything, draw only when back buffer is available. + // Suitable for fullscreen content only like fullscreen video playback and + // may work well with dmabuf backend. + CACHE_NONE = 2 + } RenderingCacheMode; + private: WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight); WindowBackBuffer* GetWaylandBufferToDraw(bool aCanSwitchBuffer); @@ -215,6 +230,7 @@ class WindowSurfaceWayland : public WindowSurface { bool mBufferNeedsClear; bool mIsMainThread; bool mNeedScaleFactorUpdate; + RenderingCacheMode mRenderingCacheMode; static bool UseDMABufBackend(); static bool mUseDMABufInitialized; diff --git a/widget/gtk/nsWaylandDisplay.cpp b/widget/gtk/nsWaylandDisplay.cpp index c76a304da21c..74a52845adcd 100644 --- a/widget/gtk/nsWaylandDisplay.cpp +++ b/widget/gtk/nsWaylandDisplay.cpp @@ -13,10 +13,15 @@ namespace widget { #define GBMLIB_NAME "libgbm.so.1" #define DRMLIB_NAME "libdrm.so.2" +#define DMABUF_PREF "widget.wayland_dmabuf_backend.enabled" +// See WindowSurfaceWayland::RenderingCacheMode for details. +#define CACHE_MODE_PREF "widget.wayland_cache_mode" + bool nsWaylandDisplay::mIsDMABufEnabled = false; // -1 mean the pref was not loaded yet int nsWaylandDisplay::mIsDMABufPrefState = -1; bool nsWaylandDisplay::mIsDMABufConfigured = false; +int nsWaylandDisplay::mRenderingCacheModePref = -1; wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay) { if (!aGdkDisplay) { @@ -317,14 +322,15 @@ nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay) wl_registry_add_listener(mRegistry, ®istry_listener, this); if (NS_IsMainThread()) { - // We can't load the preference from compositor/render thread, - // only from main one. So we can't call it directly from - // nsWaylandDisplay::IsDMABufEnabled() as it can be called from various - // threads. + // We can't load the preference from compositor/render thread + // so load all Wayland prefs here. if (mIsDMABufPrefState == -1) { - mIsDMABufPrefState = - Preferences::GetBool("widget.wayland_dmabuf_backend.enabled", false); + mIsDMABufPrefState = Preferences::GetBool(DMABUF_PREF, false); } + if (mRenderingCacheModePref == -1) { + mRenderingCacheModePref = Preferences::GetInt(CACHE_MODE_PREF, 0); + } + // Use default event queue in main thread operated by Gtk+. mEventQueue = nullptr; wl_display_roundtrip(mDisplay); diff --git a/widget/gtk/nsWaylandDisplay.h b/widget/gtk/nsWaylandDisplay.h index aae01bc168eb..ecf530608d26 100644 --- a/widget/gtk/nsWaylandDisplay.h +++ b/widget/gtk/nsWaylandDisplay.h @@ -77,6 +77,9 @@ class nsWaylandDisplay { uint32_t mModifierLo); static bool IsDMABufEnabled(); + // See WindowSurfaceWayland::CacheMode for details. + int GetRenderingCacheModePref() { return mRenderingCacheModePref; }; + private: bool ConfigureGbm(); @@ -100,6 +103,7 @@ class nsWaylandDisplay { static bool mIsDMABufEnabled; static int mIsDMABufPrefState; static bool mIsDMABufConfigured; + static int mRenderingCacheModePref; }; void WaylandDispatchDisplays(); diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp index 492dea155bd0..06d082b2980f 100644 --- a/xpfe/appshell/nsWebShellWindow.cpp +++ b/xpfe/appshell/nsWebShellWindow.cpp @@ -210,11 +210,15 @@ nsresult nsWebShellWindow::Initialize( nsIWebProgress::NOTIFY_STATE_NETWORK); } +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED if (aOpenerWindow) { - nsPIDOMWindowOuter* window = mDocShell->GetWindow(); - MOZ_ASSERT(window); - window->SetOpenerWindow(nsPIDOMWindowOuter::From(aOpenerWindow), true); + BrowsingContext* bc = mDocShell->GetBrowsingContext(); + BrowsingContext* openerBC = + nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext(); + MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == openerBC->Id()); + MOZ_DIAGNOSTIC_ASSERT(bc->HadOriginalOpener()); } +#endif // Eagerly create an about:blank content viewer with the right principal here, // rather than letting it happening in the upcoming call to