mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1832306 - Make BrowserParent
stop handling access keys with delayed events r=smaug,NeilDeakin
`EventStateManager::WalkESMTreeToHandleAccessKey()` requests all `BrowserParent` instances to handle access key in content processes: https://searchfox.org/mozilla-central/rev/a4fd6daad3a4123d995478467c1274653b283801/dom/events/EventStateManager.cpp#1379,1398,1410-1411 Then, content processes will reply if no element matches with the access key: https://searchfox.org/mozilla-central/rev/8e1b221afcdae76284b1439c547b032d1f84d236/dom/ipc/BrowserChild.cpp#2304-2305,2310 Finally, the parent process handles the keypress event: https://searchfox.org/mozilla-central/rev/8e1b221afcdae76284b1439c547b032d1f84d236/dom/ipc/BrowserParent.cpp#2710-2712,2720,2725 However, this is odd because if multiple remote processes calls `BrowserParent::RecvAccessKeyNotHandled()`, the parent process will handle same `keypress` event multiple times. The approach of this patch is, `BrowserParent` should store main data of sending `eKeyPress` event, and `RecvAccessKeyNotHandled()` handles only if the coming event matches with the stored one and clear the data to avoid handling multiple times. Even with this approach, we cannot avoid one `eKeyPress` event handled in multiple content processes, or in both the main process and a content process. Differential Revision: https://phabricator.services.mozilla.com/D179172
This commit is contained in:
parent
eb795dabb9
commit
828d108d6f
@ -8,6 +8,7 @@
|
||||
|
||||
#include "BrowserParent.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
# include "mozilla/a11y/DocAccessibleParent.h"
|
||||
@ -46,6 +47,7 @@
|
||||
#include "mozilla/layers/InputAPZContext.h"
|
||||
#include "mozilla/layout/RemoteLayerTreeOwner.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/NativeKeyBindingsType.h"
|
||||
@ -181,7 +183,79 @@ BrowserParent* BrowserParent::sLastMouseRemoteTarget = nullptr;
|
||||
// from the ones registered by webProgressListeners.
|
||||
#define NOTIFY_FLAG_SHIFT 16
|
||||
|
||||
namespace mozilla::dom {
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Store data of a keypress event which is requesting to handled it in a remote
|
||||
* process or some remote processes.
|
||||
*/
|
||||
class RequestingAccessKeyEventData {
|
||||
public:
|
||||
RequestingAccessKeyEventData() = delete;
|
||||
|
||||
static void OnBrowserParentCreated() {
|
||||
MOZ_ASSERT(sBrowserParentCount <= INT32_MAX);
|
||||
sBrowserParentCount++;
|
||||
}
|
||||
static void OnBrowserParentDestroyed() {
|
||||
MOZ_ASSERT(sBrowserParentCount > 0);
|
||||
sBrowserParentCount--;
|
||||
// To avoid memory leak, we need to reset sData when the last BrowserParent
|
||||
// is destroyed.
|
||||
if (!sBrowserParentCount) {
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
|
||||
static void Set(const WidgetKeyboardEvent& aKeyPressEvent) {
|
||||
MOZ_ASSERT(aKeyPressEvent.mMessage == eKeyPress);
|
||||
MOZ_ASSERT(sBrowserParentCount > 0);
|
||||
sData =
|
||||
Some(Data{aKeyPressEvent.mAlternativeCharCodes, aKeyPressEvent.mKeyCode,
|
||||
aKeyPressEvent.mCharCode, aKeyPressEvent.mKeyNameIndex,
|
||||
aKeyPressEvent.mCodeNameIndex, aKeyPressEvent.mKeyValue,
|
||||
aKeyPressEvent.mModifiers});
|
||||
}
|
||||
|
||||
static void Clear() { sData.reset(); }
|
||||
|
||||
[[nodiscard]] static bool Equals(const WidgetKeyboardEvent& aKeyPressEvent) {
|
||||
MOZ_ASSERT(sBrowserParentCount > 0);
|
||||
return sData.isSome() && sData->Equals(aKeyPressEvent);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool IsSet() {
|
||||
MOZ_ASSERT(sBrowserParentCount > 0);
|
||||
return sData.isSome();
|
||||
}
|
||||
|
||||
private:
|
||||
struct Data {
|
||||
[[nodiscard]] bool Equals(const WidgetKeyboardEvent& aKeyPressEvent) {
|
||||
return mKeyCode == aKeyPressEvent.mKeyCode &&
|
||||
mCharCode == aKeyPressEvent.mCharCode &&
|
||||
mKeyNameIndex == aKeyPressEvent.mKeyNameIndex &&
|
||||
mCodeNameIndex == aKeyPressEvent.mCodeNameIndex &&
|
||||
mKeyValue == aKeyPressEvent.mKeyValue &&
|
||||
mModifiers == aKeyPressEvent.mModifiers &&
|
||||
mAlternativeCharCodes == aKeyPressEvent.mAlternativeCharCodes;
|
||||
}
|
||||
|
||||
CopyableTArray<AlternativeCharCode> mAlternativeCharCodes;
|
||||
uint32_t mKeyCode;
|
||||
uint32_t mCharCode;
|
||||
KeyNameIndex mKeyNameIndex;
|
||||
CodeNameIndex mCodeNameIndex;
|
||||
nsString mKeyValue;
|
||||
Modifiers mModifiers;
|
||||
};
|
||||
static Maybe<Data> sData;
|
||||
static int32_t sBrowserParentCount;
|
||||
};
|
||||
int32_t RequestingAccessKeyEventData::sBrowserParentCount = 0;
|
||||
Maybe<RequestingAccessKeyEventData::Data> RequestingAccessKeyEventData::sData;
|
||||
|
||||
namespace dom {
|
||||
|
||||
BrowserParent::LayerToBrowserParentTable*
|
||||
BrowserParent::sLayerToBrowserParentTable = nullptr;
|
||||
@ -238,6 +312,9 @@ BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
|
||||
mLockedNativePointer(false),
|
||||
mShowingTooltip(false) {
|
||||
MOZ_ASSERT(aManager);
|
||||
|
||||
RequestingAccessKeyEventData::OnBrowserParentCreated();
|
||||
|
||||
// When the input event queue is disabled, we don't need to handle the case
|
||||
// that some input events are dispatched before PBrowserConstructor.
|
||||
mIsReadyToHandleInputEvents = !ContentParent::IsInputEventQueueSupported();
|
||||
@ -259,7 +336,9 @@ BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
|
||||
}
|
||||
}
|
||||
|
||||
BrowserParent::~BrowserParent() = default;
|
||||
BrowserParent::~BrowserParent() {
|
||||
RequestingAccessKeyEventData::OnBrowserParentDestroyed();
|
||||
}
|
||||
|
||||
/* static */
|
||||
BrowserParent* BrowserParent::GetFocused() { return sFocus; }
|
||||
@ -1100,6 +1179,7 @@ void BrowserParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
|
||||
// because the event may be dispatched to it as normal keyboard event.
|
||||
// Therefore, we should use local copy to send it.
|
||||
WidgetKeyboardEvent localEvent(aEvent);
|
||||
RequestingAccessKeyEventData::Set(localEvent);
|
||||
Unused << SendHandleAccessKey(localEvent, aCharCodes);
|
||||
}
|
||||
}
|
||||
@ -2718,11 +2798,27 @@ mozilla::ipc::IPCResult BrowserParent::RecvAccessKeyNotHandled(
|
||||
// This is called only when this process had focus and HandleAccessKey
|
||||
// message was posted to all remote process and each remote process didn't
|
||||
// execute any content access keys.
|
||||
// XXX If there were two or more remote processes, this may be called
|
||||
// twice or more for a keyboard event, that must be a bug. But how to
|
||||
// detect if received event has already been handled?
|
||||
|
||||
MOZ_ASSERT(aEvent.mMessage == eKeyPress);
|
||||
if (MOZ_UNLIKELY(aEvent.mMessage != eKeyPress || !aEvent.IsTrusted())) {
|
||||
return IPC_FAIL(this, "Called with unexpected event");
|
||||
}
|
||||
|
||||
// If there is no requesting event, the event may have already been handled
|
||||
// when it's returned from another remote process.
|
||||
if (MOZ_UNLIKELY(!RequestingAccessKeyEventData::IsSet())) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// If the event does not match with the one which we requested a remote
|
||||
// process to handle access key of (that means that we has already requested
|
||||
// for another key press), we should ignore this call because user focuses
|
||||
// to the last key press.
|
||||
if (MOZ_UNLIKELY(!RequestingAccessKeyEventData::Equals(aEvent))) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
RequestingAccessKeyEventData::Clear();
|
||||
|
||||
WidgetKeyboardEvent localEvent(aEvent);
|
||||
localEvent.MarkAsHandledInRemoteProcess();
|
||||
localEvent.mMessage = eAccessKeyNotFound;
|
||||
@ -4010,4 +4106,5 @@ mozilla::ipc::IPCResult BrowserParent::RecvShowDynamicToolbar() {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -80,12 +80,21 @@ enum class AccessKeyType {
|
||||
******************************************************************************/
|
||||
|
||||
struct AlternativeCharCode {
|
||||
AlternativeCharCode() : mUnshiftedCharCode(0), mShiftedCharCode(0) {}
|
||||
AlternativeCharCode() = default;
|
||||
AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode)
|
||||
: mUnshiftedCharCode(aUnshiftedCharCode),
|
||||
mShiftedCharCode(aShiftedCharCode) {}
|
||||
uint32_t mUnshiftedCharCode;
|
||||
uint32_t mShiftedCharCode;
|
||||
|
||||
uint32_t mUnshiftedCharCode = 0u;
|
||||
uint32_t mShiftedCharCode = 0u;
|
||||
|
||||
bool operator==(const AlternativeCharCode& aOther) const {
|
||||
return mUnshiftedCharCode == aOther.mUnshiftedCharCode &&
|
||||
mShiftedCharCode == aOther.mShiftedCharCode;
|
||||
}
|
||||
bool operator!=(const AlternativeCharCode& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
|
Loading…
Reference in New Issue
Block a user