Bug 1873330 - Part 4: Add UserActivation::Modifiers getters. r=smaug

In order to use the modifiers in nsGlobalWindowOuter::OpenInternal, add accessor
methods to BrowsingContext, Document, and WindowContext.
Those accessors behave in the same way as ConsumeTransientUserGestureActivation
and RevisePopupAbuseLevel, except for checking the PopupBlocker state.

Differential Revision: https://phabricator.services.mozilla.com/D197862
This commit is contained in:
Tooru Fujisawa 2024-01-11 17:24:02 +00:00
parent 1eb9eb9c1a
commit da72302e92
6 changed files with 71 additions and 25 deletions

View File

@ -2172,12 +2172,28 @@ void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
}
}
/*
* Examine the current document state to see if we're in a way that is
* typically abused by web designers. The window.open code uses this
* routine to determine whether to allow the new window.
* Returns a value from the PopupControlState enum.
*/
template <typename FuncT>
inline bool ApplyToDocumentsForPopup(Document* doc, FuncT func) {
// HACK: Some pages using bogus library + UA sniffing call window.open()
// from a blank iframe, only on Firefox, see bug 1685056.
//
// This is a hack-around to preserve behavior in that particular and
// specific case, by consuming activation on the parent document, so we
// don't care about the InProcessParent bits not being fission-safe or what
// not.
if (func(doc)) {
return true;
}
if (!doc->IsInitialDocument()) {
return false;
}
Document* parentDoc = doc->GetInProcessParentDocument();
if (!parentDoc || !parentDoc->NodePrincipal()->Equals(doc->NodePrincipal())) {
return false;
}
return func(parentDoc);
}
PopupBlocker::PopupControlState BrowsingContext::RevisePopupAbuseLevel(
PopupBlocker::PopupControlState aControl) {
if (!IsContent()) {
@ -2220,27 +2236,11 @@ PopupBlocker::PopupControlState BrowsingContext::RevisePopupAbuseLevel(
// If we're currently in-process, attempt to consume transient user gesture
// activations.
if (doc) {
// HACK: Some pages using bogus library + UA sniffing call window.open()
// from a blank iframe, only on Firefox, see bug 1685056.
//
// This is a hack-around to preserve behavior in that particular and
// specific case, by consuming activation on the parent document, so we
// don't care about the InProcessParent bits not being fission-safe or what
// not.
auto ConsumeTransientUserActivationForMultiplePopupBlocking =
[&]() -> bool {
if (doc->ConsumeTransientUserGestureActivation()) {
return true;
}
if (!doc->IsInitialDocument()) {
return false;
}
Document* parentDoc = doc->GetInProcessParentDocument();
if (!parentDoc ||
!parentDoc->NodePrincipal()->Equals(doc->NodePrincipal())) {
return false;
}
return parentDoc->ConsumeTransientUserGestureActivation();
return ApplyToDocumentsForPopup(doc, [](Document* doc) {
return doc->ConsumeTransientUserGestureActivation();
});
};
// If this popup is allowed, let's block any other for this event, forcing
@ -2259,6 +2259,18 @@ PopupBlocker::PopupControlState BrowsingContext::RevisePopupAbuseLevel(
return abuse;
}
void BrowsingContext::GetUserActivationModifiersForPopup(
UserActivation::Modifiers* aModifiers) {
RefPtr<Document> doc = GetExtantDocument();
if (doc) {
// Unlike RevisePopupAbuseLevel, modifiers can always be used regardless
// of PopupControlState.
(void)ApplyToDocumentsForPopup(doc, [&](Document* doc) {
return doc->GetTransientUserGestureActivationModifiers(aModifiers);
});
}
}
void BrowsingContext::IncrementHistoryEntryCountForBrowsingContext() {
Unused << SetHistoryEntryCount(GetHistoryEntryCount() + 1);
}

View File

@ -906,9 +906,19 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
bool CanBlurCheck(CallerType aCallerType);
// Examine the current document state to see if we're in a way that is
// typically abused by web designers. The window.open code uses this
// routine to determine whether to allow the new window.
// Returns a value from the PopupControlState enum.
PopupBlocker::PopupControlState RevisePopupAbuseLevel(
PopupBlocker::PopupControlState aControl);
// Get the modifiers associated with the user activation for relevant
// documents. The window.open code uses this routine to determine where the
// new window should be located.
void GetUserActivationModifiersForPopup(
UserActivation::Modifiers* aModifiers);
void IncrementHistoryEntryCountForBrowsingContext();
bool ServiceWorkersTestingEnabled() const {

View File

@ -552,6 +552,18 @@ bool WindowContext::ConsumeTransientUserGestureActivation() {
return true;
}
bool WindowContext::GetTransientUserGestureActivationModifiers(
UserActivation::Modifiers* aModifiers) {
if (!HasValidTransientUserGestureActivation()) {
return false;
}
auto stateAndModifiers =
UserActivation::StateAndModifiers(GetUserActivationStateAndModifiers());
*aModifiers = stateAndModifiers.GetModifiers();
return true;
}
bool WindowContext::CanShowPopup() {
uint32_t permit = GetPopupPermission();
if (permit == nsIPermissionManager::ALLOW_ACTION) {

View File

@ -227,6 +227,9 @@ class WindowContext : public nsISupports, public nsWrapperCache {
// successfully.
bool ConsumeTransientUserGestureActivation();
bool GetTransientUserGestureActivationModifiers(
UserActivation::Modifiers* aModifiers);
bool CanShowPopup();
bool AllowJavascript() const { return GetAllowJavascript(); }

View File

@ -16842,6 +16842,12 @@ bool Document::ConsumeTransientUserGestureActivation() {
return wc && wc->ConsumeTransientUserGestureActivation();
}
bool Document::GetTransientUserGestureActivationModifiers(
UserActivation::Modifiers* aModifiers) {
RefPtr<WindowContext> wc = GetWindowContext();
return wc && wc->GetTransientUserGestureActivationModifiers(aModifiers);
}
void Document::SetDocTreeHadMedia() {
RefPtr<WindowContext> topWc = GetTopLevelWindowContext();
if (topWc && !topWc->IsDiscarded() && !topWc->GetDocTreeHadMedia()) {

View File

@ -3665,6 +3665,9 @@ class Document : public nsINode,
// and consume the activation.
bool ConsumeTransientUserGestureActivation();
bool GetTransientUserGestureActivationModifiers(
UserActivation::Modifiers* aModifiers);
BrowsingContext* GetBrowsingContext() const;
// This document is a WebExtension page, it might be a background page, a