Bug 1333459 - part1: Move methods of EventStateManager which check modifiers of access key to WidgetKeyboardEvent r=smaug

EventStateManager checks if every keypress event's modifiers match with access key modifiers which are in prefs. Moving related methods of this to WidgetKeyboardEvent makes EventStateManager simpler and we can hide the NS_MODIFIER_* constants (they may make developers confused between Modifiers of WidgetInputEvent) into WidgetEventImpl.cpp.

MozReview-Commit-ID: 23NUQ51lJ1M

--HG--
extra : rebase_source : 341f3764ef62575577572d8b349159e2d5512b26
This commit is contained in:
Masayuki Nakano 2017-07-06 17:36:19 +09:00
Родитель a7be68f59a
Коммит 6c68caecd7
10 изменённых файлов: 213 добавлений и 162 удалений

Просмотреть файл

@ -186,13 +186,6 @@ PrintDocTreeAll(nsIDocShellTreeItem* aItem)
}
#endif
// mask values for ui.key.chromeAccess and ui.key.contentAccess
#define NS_MODIFIER_SHIFT 1
#define NS_MODIFIER_CONTROL 2
#define NS_MODIFIER_ALT 4
#define NS_MODIFIER_META 8
#define NS_MODIFIER_OS 16
/******************************************************************/
/* mozilla::UITimerCallback */
/******************************************************************/
@ -768,32 +761,13 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
case eKeyPress:
{
WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
AutoTArray<uint32_t, 10> accessCharCodes;
keyEvent->GetAccessKeyCandidates(accessCharCodes);
int32_t modifierMask = 0;
if (keyEvent->IsShift())
modifierMask |= NS_MODIFIER_SHIFT;
if (keyEvent->IsControl())
modifierMask |= NS_MODIFIER_CONTROL;
if (keyEvent->IsAlt())
modifierMask |= NS_MODIFIER_ALT;
if (keyEvent->IsMeta())
modifierMask |= NS_MODIFIER_META;
if (keyEvent->IsOS())
modifierMask |= NS_MODIFIER_OS;
// Prevent keyboard scrolling while an accesskey modifier is in use.
if (modifierMask) {
bool matchesContentAccessKey = (modifierMask == Prefs::ContentAccessModifierMask());
if (modifierMask == Prefs::ChromeAccessModifierMask() ||
matchesContentAccessKey) {
AutoTArray<uint32_t, 10> accessCharCodes;
keyEvent->GetAccessKeyCandidates(accessCharCodes);
if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes,
modifierMask, matchesContentAccessKey)) {
*aStatus = nsEventStatus_eConsumeNoDefault;
}
if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes)) {
*aStatus = nsEventStatus_eConsumeNoDefault;
}
}
}
@ -924,23 +898,21 @@ EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
handler.HandleQueryContentEvent(aEvent);
}
// static
int32_t
EventStateManager::GetAccessModifierMaskFor(nsISupports* aDocShell)
static AccessKeyType
GetAccessKeyTypeFor(nsISupports* aDocShell)
{
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
if (!treeItem)
return -1; // invalid modifier
if (!treeItem) {
return AccessKeyType::eNone;
}
switch (treeItem->ItemType()) {
case nsIDocShellTreeItem::typeChrome:
return Prefs::ChromeAccessModifierMask();
case nsIDocShellTreeItem::typeContent:
return Prefs::ContentAccessModifierMask();
default:
return -1; // invalid modifier
case nsIDocShellTreeItem::typeChrome:
return AccessKeyType::eChrome;
case nsIDocShellTreeItem::typeContent:
return AccessKeyType::eContent;
default:
return AccessKeyType::eNone;
}
}
@ -1059,30 +1031,33 @@ EventStateManager::GetAccessKeyLabelPrefix(Element* aElement, nsAString& aPrefix
nsAutoString separator, modifierText;
nsContentUtils::GetModifierSeparatorText(separator);
nsCOMPtr<nsISupports> container = aElement->OwnerDoc()->GetDocShell();
int32_t modifierMask = GetAccessModifierMaskFor(container);
if (modifierMask == -1) {
AccessKeyType accessKeyType =
GetAccessKeyTypeFor(aElement->OwnerDoc()->GetDocShell());
if (accessKeyType == AccessKeyType::eNone) {
return;
}
Modifiers modifiers = WidgetKeyboardEvent::AccessKeyModifiers(accessKeyType);
if (modifiers == MODIFIER_NONE) {
return;
}
if (modifierMask & NS_MODIFIER_CONTROL) {
if (modifiers & MODIFIER_CONTROL) {
nsContentUtils::GetControlText(modifierText);
aPrefix.Append(modifierText + separator);
}
if (modifierMask & NS_MODIFIER_META) {
if (modifiers & MODIFIER_META) {
nsContentUtils::GetMetaText(modifierText);
aPrefix.Append(modifierText + separator);
}
if (modifierMask & NS_MODIFIER_OS) {
if (modifiers & MODIFIER_OS) {
nsContentUtils::GetOSText(modifierText);
aPrefix.Append(modifierText + separator);
}
if (modifierMask & NS_MODIFIER_ALT) {
if (modifiers & MODIFIER_ALT) {
nsContentUtils::GetAltText(modifierText);
aPrefix.Append(modifierText + separator);
}
if (modifierMask & NS_MODIFIER_SHIFT) {
if (modifiers & MODIFIER_SHIFT) {
nsContentUtils::GetShiftText(modifierText);
aPrefix.Append(modifierText + separator);
}
@ -1092,12 +1067,11 @@ struct MOZ_STACK_CLASS AccessKeyInfo
{
WidgetKeyboardEvent* event;
nsTArray<uint32_t>& charCodes;
int32_t modifierMask;
AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes, int32_t aModifierMask)
AccessKeyInfo(WidgetKeyboardEvent* aEvent,
nsTArray<uint32_t>& aCharCodes)
: event(aEvent)
, charCodes(aCharCodes)
, modifierMask(aModifierMask)
{
}
};
@ -1113,8 +1087,7 @@ HandleAccessKeyInRemoteChild(TabParent* aTabParent, void* aArg)
if (active) {
accessKeyInfo->event->mAccessKeyForwardedToChild = true;
aTabParent->HandleAccessKey(*accessKeyInfo->event,
accessKeyInfo->charCodes,
accessKeyInfo->modifierMask);
accessKeyInfo->charCodes);
return true;
}
@ -1125,20 +1098,21 @@ bool
EventStateManager::HandleAccessKey(WidgetKeyboardEvent* aEvent,
nsPresContext* aPresContext,
nsTArray<uint32_t>& aAccessCharCodes,
bool aMatchesContentAccessKey,
nsIDocShellTreeItem* aBubbledFrom,
ProcessingAccessKeyState aAccessKeyState,
int32_t aModifierMask)
ProcessingAccessKeyState aAccessKeyState)
{
EnsureDocument(mPresContext);
nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
if (NS_WARN_IF(!docShell) || NS_WARN_IF(!mDocument)) {
return false;
}
AccessKeyType accessKeyType = GetAccessKeyTypeFor(docShell);
if (accessKeyType == AccessKeyType::eNone) {
return false;
}
// Alt or other accesskey modifier is down, we may need to do an accesskey.
if (mAccessKeys.Count() > 0 &&
aModifierMask == GetAccessModifierMaskFor(docShell)) {
aEvent->ModifiersMatchWithAccessKey(accessKeyType)) {
// Someone registered an accesskey. Find and activate it.
if (ExecuteAccessKey(aAccessCharCodes, aEvent->IsTrusted())) {
return true;
@ -1174,8 +1148,7 @@ EventStateManager::HandleAccessKey(WidgetKeyboardEvent* aEvent,
if (esm &&
esm->HandleAccessKey(aEvent, subPC, aAccessCharCodes,
aMatchesContentAccessKey, nullptr,
eAccessKeyProcessingDown, aModifierMask)) {
nullptr, eAccessKeyProcessingDown)) {
return true;
}
}
@ -1197,15 +1170,15 @@ EventStateManager::HandleAccessKey(WidgetKeyboardEvent* aEvent,
static_cast<EventStateManager*>(parentPC->EventStateManager());
if (esm &&
esm->HandleAccessKey(aEvent, parentPC, aAccessCharCodes,
aMatchesContentAccessKey, docShell,
eAccessKeyProcessingDown, aModifierMask)) {
docShell, eAccessKeyProcessingDown)) {
return true;
}
}
}// if end. bubble up process
// If the content access key modifier is pressed, try remote children
if (aMatchesContentAccessKey && mDocument && mDocument->GetWindow()) {
if (aEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent) &&
mDocument && mDocument->GetWindow()) {
// If the focus is currently on a node with a TabParent, the key event will
// get forwarded to the child process and HandleAccessKey called from there.
// If focus is somewhere else, then we need to check the remote children.
@ -1216,9 +1189,10 @@ EventStateManager::HandleAccessKey(WidgetKeyboardEvent* aEvent,
// the child process.
aEvent->mAccessKeyForwardedToChild = true;
} else {
AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes, aModifierMask);
AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes);
nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
HandleAccessKeyInRemoteChild, &accessKeyInfo);
HandleAccessKeyInRemoteChild,
&accessKeyInfo);
}
}
@ -5819,9 +5793,6 @@ EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
bool EventStateManager::Prefs::sKeyCausesActivation = true;
bool EventStateManager::Prefs::sClickHoldContextMenu = false;
int32_t EventStateManager::Prefs::sGenericAccessModifierKey = -1;
int32_t EventStateManager::Prefs::sChromeAccessModifierMask = 0;
int32_t EventStateManager::Prefs::sContentAccessModifierMask = 0;
// static
void
@ -5846,21 +5817,6 @@ EventStateManager::Prefs::Init()
sClickHoldContextMenu);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to observe \"ui.click_hold_context_menus\"");
rv = Preferences::AddIntVarCache(&sGenericAccessModifierKey,
"ui.key.generalAccessKey",
sGenericAccessModifierKey);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to observe \"ui.key.generalAccessKey\"");
rv = Preferences::AddIntVarCache(&sChromeAccessModifierMask,
"ui.key.chromeAccess",
sChromeAccessModifierMask);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to observe \"ui.key.chromeAccess\"");
rv = Preferences::AddIntVarCache(&sContentAccessModifierMask,
"ui.key.contentAccess",
sContentAccessModifierMask);
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to observe \"ui.key.contentAccess\"");
sPrefsAlreadyCached = true;
}
@ -5881,44 +5837,6 @@ EventStateManager::Prefs::Shutdown()
Preferences::UnregisterCallback(OnChange, "dom.popup_allowed_events");
}
// static
int32_t
EventStateManager::Prefs::ChromeAccessModifierMask()
{
return GetAccessModifierMask(nsIDocShellTreeItem::typeChrome);
}
// static
int32_t
EventStateManager::Prefs::ContentAccessModifierMask()
{
return GetAccessModifierMask(nsIDocShellTreeItem::typeContent);
}
// static
int32_t
EventStateManager::Prefs::GetAccessModifierMask(int32_t aItemType)
{
switch (sGenericAccessModifierKey) {
case -1: break; // use the individual prefs
case nsIDOMKeyEvent::DOM_VK_SHIFT: return NS_MODIFIER_SHIFT;
case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
case nsIDOMKeyEvent::DOM_VK_ALT: return NS_MODIFIER_ALT;
case nsIDOMKeyEvent::DOM_VK_META: return NS_MODIFIER_META;
case nsIDOMKeyEvent::DOM_VK_WIN: return NS_MODIFIER_OS;
default: return 0;
}
switch (aItemType) {
case nsIDocShellTreeItem::typeChrome:
return sChromeAccessModifierMask;
case nsIDocShellTreeItem::typeContent:
return sContentAccessModifierMask;
default:
return 0;
}
}
/******************************************************************/
/* mozilla::AutoHandlingUserInputStatePusher */
/******************************************************************/

Просмотреть файл

@ -186,13 +186,10 @@ public:
bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
nsPresContext* aPresContext,
nsTArray<uint32_t>& aAccessCharCodes,
int32_t aModifierMask,
bool aMatchesContentAccessKey)
nsTArray<uint32_t>& aAccessCharCodes)
{
return HandleAccessKey(aEvent, aPresContext, aAccessCharCodes,
aMatchesContentAccessKey, nullptr,
eAccessKeyProcessingNormal, aModifierMask);
nullptr, eAccessKeyProcessingNormal);
}
nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer,
@ -316,8 +313,6 @@ protected:
public:
static bool KeyCausesActivation() { return sKeyCausesActivation; }
static bool ClickHoldContextMenu() { return sClickHoldContextMenu; }
static int32_t ChromeAccessModifierMask();
static int32_t ContentAccessModifierMask();
static void Init();
static void OnChange(const char* aPrefName, void*);
@ -326,19 +321,10 @@ protected:
private:
static bool sKeyCausesActivation;
static bool sClickHoldContextMenu;
static int32_t sGenericAccessModifierKey;
static int32_t sChromeAccessModifierMask;
static int32_t sContentAccessModifierMask;
static int32_t GetAccessModifierMask(int32_t aItemType);
};
/**
* Get appropriate access modifier mask for the aDocShell. Returns -1 if
* access key isn't available.
*/
static int32_t GetAccessModifierMaskFor(nsISupports* aDocShell);
/*
* If aTargetFrame's widget has a cached cursor value, resets the cursor
* such that the next call to SetCursor on the widget will force an update
@ -449,7 +435,6 @@ protected:
* @param aEvent the keyboard event triggering the acccess key
* @param aPresContext the presentation context
* @param aAccessCharCodes list of charcode candidates
* @param aMatchesContentAccessKey true if the content accesskey modifier is pressed
* @param aBubbledFrom is used by an ancestor to avoid calling HandleAccessKey()
* on the child the call originally came from, i.e. this is the child
* that recursively called us in its Up phase. The initial caller
@ -457,15 +442,12 @@ protected:
* @param aAccessKeyState Normal, Down or Up processing phase (see enums
* above). The initial event receiver uses 'normal', then 'down' when
* processing children and Up when recursively calling its ancestor.
* @param aModifierMask modifier mask for the key event
*/
bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
nsPresContext* aPresContext,
nsTArray<uint32_t>& aAccessCharCodes,
bool aMatchesContentAccessKey,
nsIDocShellTreeItem* aBubbledFrom,
ProcessingAccessKeyState aAccessKeyState,
int32_t aModifierMask);
ProcessingAccessKeyState aAccessKeyState);
bool ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes,
bool aIsTrustedEvent);

Просмотреть файл

@ -806,10 +806,9 @@ child:
*
* @param event keyboard event
* @param isTrusted true if triggered by a trusted key event
* @param modifierMask indicates which accesskey modifiers are pressed
*/
async HandleAccessKey(WidgetKeyboardEvent event,
uint32_t[] charCodes, int32_t modifierMask);
uint32_t[] charCodes);
/**
* Tells the root child docShell whether or not to use

Просмотреть файл

@ -2244,8 +2244,7 @@ TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
mozilla::ipc::IPCResult
TabChild::RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>&& aCharCodes,
const int32_t& aModifierMask)
nsTArray<uint32_t>&& aCharCodes)
{
nsCOMPtr<nsIDocument> document(GetDocument());
nsCOMPtr<nsIPresShell> presShell = document->GetShell();
@ -2254,8 +2253,7 @@ TabChild::RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
if (pc) {
if (!pc->EventStateManager()->
HandleAccessKey(&(const_cast<WidgetKeyboardEvent&>(aEvent)),
pc, aCharCodes,
aModifierMask, true)) {
pc, aCharCodes)) {
// If no accesskey was found, inform the parent so that accesskeys on
// menus can be handled.
WidgetKeyboardEvent localEvent(aEvent);

Просмотреть файл

@ -595,9 +595,9 @@ public:
virtual mozilla::ipc::IPCResult
RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
virtual mozilla::ipc::IPCResult RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>&& aCharCodes,
const int32_t& aModifierMask) override;
virtual mozilla::ipc::IPCResult
RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>&& aCharCodes) override;
virtual mozilla::ipc::IPCResult RecvSetUseGlobalHistory(const bool& aUse) override;

Просмотреть файл

@ -817,15 +817,14 @@ TabParent::ThemeChanged()
void
TabParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>& aCharCodes,
const int32_t& aModifierMask)
nsTArray<uint32_t>& aCharCodes)
{
if (!mIsDestroyed) {
// Note that we don't need to mark aEvent is posted to a remote process
// because the event may be dispatched to it as normal keyboard event.
// Therefore, we should use local copy to send it.
WidgetKeyboardEvent localEvent(aEvent);
Unused << SendHandleAccessKey(localEvent, aCharCodes, aModifierMask);
Unused << SendHandleAccessKey(localEvent, aCharCodes);
}
}

Просмотреть файл

@ -361,8 +361,7 @@ public:
void ThemeChanged();
void HandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>& aCharCodes,
const int32_t& aModifierMask);
nsTArray<uint32_t>& aCharCodes);
void Activate();

Просмотреть файл

@ -150,6 +150,8 @@ class WidgetEventTime;
class NativeEventData;
// TextEvents.h
enum class AccessKeyType;
struct AlternativeCharCode;
struct ShortcutKeyCandidate;

Просмотреть файл

@ -59,6 +59,16 @@ namespace plugins {
class PPluginInstanceChild;
} // namespace plugins
enum class AccessKeyType
{
// Handle access key for chrome.
eChrome,
// Handle access key for content.
eContent,
// Don't handle access key.
eNone
};
/******************************************************************************
* mozilla::AlternativeCharCode
*
@ -431,6 +441,24 @@ public:
*/
void GetAccessKeyCandidates(nsTArray<uint32_t>& aCandidates) const;
/**
* Check whether the modifiers match with chrome access key or
* content access key.
*/
bool ModifiersMatchWithAccessKey(AccessKeyType aType) const;
/**
* Return active modifiers which may match with access key.
* For example, even if Alt is access key modifier, then, when Control,
* CapseLock and NumLock are active, this returns only MODIFIER_CONTROL.
*/
Modifiers ModifiersForAccessKeyMatching() const;
/**
* Return access key modifiers.
*/
static Modifiers AccessKeyModifiers(AccessKeyType aType);
static void Shutdown();
/**
@ -565,6 +593,10 @@ private:
"Invalid native key binding type");
}
}
static int32_t GenericAccessModifierKeyPref();
static int32_t ChromeAccessModifierMaskPref();
static int32_t ContentAccessModifierMaskPref();
};
/******************************************************************************

Просмотреть файл

@ -869,6 +869,128 @@ WidgetKeyboardEvent::GetAccessKeyCandidates(nsTArray<uint32_t>& aCandidates) con
}
}
// mask values for ui.key.chromeAccess and ui.key.contentAccess
#define NS_MODIFIER_SHIFT 1
#define NS_MODIFIER_CONTROL 2
#define NS_MODIFIER_ALT 4
#define NS_MODIFIER_META 8
#define NS_MODIFIER_OS 16
static Modifiers PrefFlagsToModifiers(int32_t aPrefFlags)
{
Modifiers result = 0;
if (aPrefFlags & NS_MODIFIER_SHIFT) {
result |= MODIFIER_SHIFT;
}
if (aPrefFlags & NS_MODIFIER_CONTROL) {
result |= MODIFIER_CONTROL;
}
if (aPrefFlags & NS_MODIFIER_ALT) {
result |= MODIFIER_ALT;
}
if (aPrefFlags & NS_MODIFIER_META) {
result |= MODIFIER_META;
}
if (aPrefFlags & NS_MODIFIER_OS) {
result |= MODIFIER_OS;
}
return result;
}
bool
WidgetKeyboardEvent::ModifiersMatchWithAccessKey(AccessKeyType aType) const
{
if (!ModifiersForAccessKeyMatching()) {
return false;
}
return ModifiersForAccessKeyMatching() == AccessKeyModifiers(aType);
}
Modifiers
WidgetKeyboardEvent::ModifiersForAccessKeyMatching() const
{
static const Modifiers kModifierMask =
MODIFIER_SHIFT | MODIFIER_CONTROL |
MODIFIER_ALT | MODIFIER_META | MODIFIER_OS;
return mModifiers & kModifierMask;
}
/* static */
Modifiers
WidgetKeyboardEvent::AccessKeyModifiers(AccessKeyType aType)
{
switch (GenericAccessModifierKeyPref()) {
case -1:
break; // use the individual prefs
case NS_VK_SHIFT:
return MODIFIER_SHIFT;
case NS_VK_CONTROL:
return MODIFIER_CONTROL;
case NS_VK_ALT:
return MODIFIER_ALT;
case NS_VK_META:
return MODIFIER_META;
case NS_VK_WIN:
return MODIFIER_OS;
default:
return MODIFIER_NONE;
}
switch (aType) {
case AccessKeyType::eChrome:
return PrefFlagsToModifiers(ChromeAccessModifierMaskPref());
case AccessKeyType::eContent:
return PrefFlagsToModifiers(ContentAccessModifierMaskPref());
default:
return MODIFIER_NONE;
}
}
/* static */
int32_t
WidgetKeyboardEvent::GenericAccessModifierKeyPref()
{
static bool sInitialized = false;
static int32_t sValue = -1;
if (!sInitialized) {
nsresult rv =
Preferences::AddIntVarCache(&sValue, "ui.key.generalAccessKey", sValue);
sInitialized = NS_SUCCEEDED(rv);
MOZ_ASSERT(sInitialized);
}
return sValue;
}
/* static */
int32_t
WidgetKeyboardEvent::ChromeAccessModifierMaskPref()
{
static bool sInitialized = false;
static int32_t sValue = 0;
if (!sInitialized) {
nsresult rv =
Preferences::AddIntVarCache(&sValue, "ui.key.chromeAccess", sValue);
sInitialized = NS_SUCCEEDED(rv);
MOZ_ASSERT(sInitialized);
}
return sValue;
}
/* static */
int32_t
WidgetKeyboardEvent::ContentAccessModifierMaskPref()
{
static bool sInitialized = false;
static int32_t sValue = 0;
if (!sInitialized) {
nsresult rv =
Preferences::AddIntVarCache(&sValue, "ui.key.contentAccess", sValue);
sInitialized = NS_SUCCEEDED(rv);
MOZ_ASSERT(sInitialized);
}
return sValue;
}
/* static */ void
WidgetKeyboardEvent::Shutdown()
{