From aeb2eac8f0ea18dec1ef00f7d614d3f52c94a3b4 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Thu, 11 Jan 2024 17:24:01 +0000 Subject: [PATCH] Bug 1873330 - Part 2: Add UserActivation::Modifiers and UserActivation::StateAndModifiers. r=smaug Associate modifier keys to user activation, in order to use the modifiers in `window.open` initiated by the user activation. Depends on D197859 Differential Revision: https://phabricator.services.mozilla.com/D197860 --- docshell/base/WindowContext.cpp | 21 ++++++---- docshell/base/WindowContext.h | 16 ++++++-- dom/base/UserActivation.h | 68 +++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/docshell/base/WindowContext.cpp b/docshell/base/WindowContext.cpp index 958654207df4..bdc1fe7ac788 100644 --- a/docshell/base/WindowContext.cpp +++ b/docshell/base/WindowContext.cpp @@ -364,11 +364,11 @@ void WindowContext::DidSet(FieldIndex, } } -void WindowContext::DidSet(FieldIndex) { +void WindowContext::DidSet(FieldIndex) { MOZ_ASSERT_IF(!IsInProcess(), mUserGestureStart.IsNull()); - USER_ACTIVATION_LOG("Set user gesture activation %" PRIu8 + USER_ACTIVATION_LOG("Set user gesture activation 0x%02" PRIu8 " for %s browsing context 0x%08" PRIx64, - static_cast(GetUserActivationState()), + GetUserActivationStateAndModifiers(), XRE_IsParentProcess() ? "Parent" : "Child", Id()); if (IsInProcess()) { USER_ACTIVATION_LOG( @@ -484,11 +484,15 @@ void WindowContext::AddSecurityState(uint32_t aStateFlags) { } void WindowContext::NotifyUserGestureActivation() { - Unused << SetUserActivationState(UserActivation::State::FullActivated); + UserActivation::StateAndModifiers stateAndModifiers; + stateAndModifiers.SetState(UserActivation::State::FullActivated); + Unused << SetUserActivationStateAndModifiers(stateAndModifiers.GetRawData()); } void WindowContext::NotifyResetUserGestureActivation() { - Unused << SetUserActivationState(UserActivation::State::None); + UserActivation::StateAndModifiers stateAndModifiers; + stateAndModifiers.SetState(UserActivation::State::None); + Unused << SetUserActivationStateAndModifiers(stateAndModifiers.GetRawData()); } bool WindowContext::HasBeenUserGestureActivated() { @@ -534,8 +538,11 @@ bool WindowContext::ConsumeTransientUserGestureActivation() { WindowContext* windowContext = aBrowsingContext->GetCurrentWindowContext(); if (windowContext && windowContext->GetUserActivationState() == UserActivation::State::FullActivated) { - Unused << windowContext->SetUserActivationState( - UserActivation::State::HasBeenActivated); + auto stateAndModifiers = UserActivation::StateAndModifiers( + GetUserActivationStateAndModifiers()); + stateAndModifiers.SetState(UserActivation::State::HasBeenActivated); + Unused << windowContext->SetUserActivationStateAndModifiers( + stateAndModifiers.GetRawData()); } }); diff --git a/docshell/base/WindowContext.h b/docshell/base/WindowContext.h index 890c658f912b..e5272ee486de 100644 --- a/docshell/base/WindowContext.h +++ b/docshell/base/WindowContext.h @@ -69,7 +69,8 @@ class BrowsingContextGroup; FIELD(HasBeforeUnload, bool) \ /* Controls whether the WindowContext is currently considered to be \ * activated by a gesture */ \ - FIELD(UserActivationState, UserActivation::State) \ + FIELD(UserActivationStateAndModifiers, \ + UserActivation::StateAndModifiers::DataT) \ FIELD(EmbedderPolicy, nsILoadInfo::CrossOriginEmbedderPolicy) \ /* True if this document tree contained at least a HTMLMediaElement. \ * This should only be set on top level context. */ \ @@ -194,6 +195,12 @@ class WindowContext : public nsISupports, public nsWrapperCache { // 'MIXED' state flags, and should only be called on the top window context. void AddSecurityState(uint32_t aStateFlags); + UserActivation::State GetUserActivationState() const { + return UserActivation::StateAndModifiers( + GetUserActivationStateAndModifiers()) + .GetState(); + } + // This function would be called when its corresponding window is activated // by user gesture. void NotifyUserGestureActivation(); @@ -310,8 +317,9 @@ class WindowContext : public nsISupports, public nsWrapperCache { bool CanSet(FieldIndex, const PermissionDelegateHandler::DelegatedPermissionList& aValue, ContentParent* aSource); - bool CanSet(FieldIndex, - const UserActivation::State& aUserActivationState, + bool CanSet(FieldIndex, + const UserActivation::StateAndModifiers::DataT& + aUserActivationStateAndModifiers, ContentParent* aSource) { return true; } @@ -344,7 +352,7 @@ class WindowContext : public nsISupports, public nsWrapperCache { void DidSet(FieldIndex) {} template void DidSet(FieldIndex, T&& aOldValue) {} - void DidSet(FieldIndex); + void DidSet(FieldIndex); // Recomputes whether we can execute scripts in this WindowContext based on // the value of AllowJavascript() and whether scripts are allowed in the diff --git a/dom/base/UserActivation.h b/dom/base/UserActivation.h index c067bbc8c3f0..6accfa71291d 100644 --- a/dom/base/UserActivation.h +++ b/dom/base/UserActivation.h @@ -7,6 +7,7 @@ #ifndef mozilla_dom_UserActivation_h #define mozilla_dom_UserActivation_h +#include "mozilla/Assertions.h" #include "mozilla/EventForwards.h" #include "mozilla/TimeStamp.h" #include "nsCycleCollectionParticipant.h" @@ -44,6 +45,73 @@ class UserActivation final : public nsISupports, public nsWrapperCache { EndGuard_ }; + class StateAndModifiers; + + // Modifier keys held while the user activation. + class Modifiers { + public: + static constexpr uint8_t Shift = 0x10; + static constexpr uint8_t Meta = 0x20; + static constexpr uint8_t Control = 0x40; + static constexpr uint8_t Alt = 0x80; + + static constexpr uint8_t Mask = 0xF0; + + constexpr Modifiers() = default; + explicit constexpr Modifiers(uint8_t aModifiers) : mModifiers(aModifiers) {} + + static constexpr Modifiers None() { return Modifiers(0); } + + uint8_t GetRawData() const { return mModifiers; } + + void SetShift() { mModifiers |= Shift; } + void SetMeta() { mModifiers |= Meta; } + void SetControl() { mModifiers |= Control; } + void SetAlt() { mModifiers |= Alt; } + + bool IsShift() const { return mModifiers & Shift; } + bool IsMeta() const { return mModifiers & Meta; } + bool IsControl() const { return mModifiers & Control; } + bool IsAlt() const { return mModifiers & Alt; } + + private: + uint8_t mModifiers = 0; + + friend class StateAndModifiers; + }; + + // State and Modifiers encoded into single data, for WindowContext field. + class StateAndModifiers { + public: + using DataT = uint8_t; + + constexpr StateAndModifiers() = default; + explicit constexpr StateAndModifiers(DataT aStateAndModifiers) + : mStateAndModifiers(aStateAndModifiers) {} + + DataT GetRawData() const { return mStateAndModifiers; } + + State GetState() const { return State(RawState()); } + void SetState(State aState) { + MOZ_ASSERT((uint8_t(aState) & Modifiers::Mask) == 0); + mStateAndModifiers = uint8_t(aState) | RawModifiers(); + } + + Modifiers GetModifiers() const { return Modifiers(RawModifiers()); } + void SetModifiers(Modifiers aModifiers) { + mStateAndModifiers = RawState() | aModifiers.mModifiers; + } + + private: + uint8_t RawState() const { return mStateAndModifiers & ~Modifiers::Mask; } + + uint8_t RawModifiers() const { + return mStateAndModifiers & Modifiers::Mask; + } + + uint8_t mStateAndModifiers = 0; + }; + /** * Returns true if the current code is being executed as a result of * user input or keyboard input. The former includes anything that is