diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp
index 3023994f2575..479a6b534fd0 100644
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -45,6 +45,9 @@
#include "nsFrameSelection.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Telemetry.h"
+#include "mozilla/ShortcutKeys.h"
+#include "nsXBLPrototypeHandler.h"
+#include "mozilla/dom/KeyboardEvent.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -957,13 +960,44 @@ TextInputListener::HandleEvent(Event* aEvent)
return NS_OK;
}
- WidgetKeyboardEvent* keyEvent =
- aEvent->WidgetEventPtr()->AsKeyboardEvent();
+ RefPtr keyEvent = aEvent->AsKeyboardEvent();
if (!keyEvent) {
return NS_ERROR_UNEXPECTED;
}
- if (keyEvent->mMessage != eKeyPress) {
+ WidgetKeyboardEvent* widgetKeyEvent =
+ aEvent->WidgetEventPtr()->AsKeyboardEvent();
+ if (!keyEvent) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsXBLPrototypeHandler* keyHandlers =
+ ShortcutKeys::GetHandlers(mTxtCtrlElement->IsTextArea() ?
+ HandlerType::eTextArea : HandlerType::eInput);
+
+ RefPtr eventTypeAtom =
+ ShortcutKeys::ConvertEventToDOMEventType(widgetKeyEvent);
+ for (nsXBLPrototypeHandler* handler = keyHandlers;
+ handler;
+ handler = handler->GetNextHandler()) {
+ if (!handler->EventTypeEquals(eventTypeAtom)) {
+ continue;
+ }
+
+ if (!handler->KeyEventMatched(keyEvent, 0, IgnoreModifierState())) {
+ continue;
+ }
+
+ // XXX Do we execute only one handler even if the handler neither stops
+ // propagation nor prevents default of the event?
+ nsCOMPtr target = do_QueryInterface(mTxtCtrlElement);
+ nsresult rv = handler->ExecuteHandler(target, aEvent);
+ if (NS_SUCCEEDED(rv)) {
+ return rv;
+ }
+ }
+
+ if (widgetKeyEvent->mMessage != eKeyPress) {
return NS_OK;
}
@@ -972,7 +1006,7 @@ TextInputListener::HandleEvent(Event* aEvent)
nsIWidget::NativeKeyBindingsForMultiLineEditor :
nsIWidget::NativeKeyBindingsForSingleLineEditor;
- nsIWidget* widget = keyEvent->mWidget;
+ nsIWidget* widget = widgetKeyEvent->mWidget;
// If the event is created by chrome script, the widget is nullptr.
if (!widget) {
widget = mFrame->GetNearestWidget();
@@ -983,10 +1017,10 @@ TextInputListener::HandleEvent(Event* aEvent)
// If the event is created by chrome script, it is nullptr but we need to
// execute native key bindings. Therefore, we need to set widget to
// WidgetEvent::mWidget temporarily.
- AutoRestore> saveWidget(keyEvent->mWidget);
- keyEvent->mWidget = widget;
- if (keyEvent->ExecuteEditCommands(nativeKeyBindingsType,
- DoCommandCallback, mFrame)) {
+ AutoRestore> saveWidget(widgetKeyEvent->mWidget);
+ widgetKeyEvent->mWidget = widget;
+ if (widgetKeyEvent->ExecuteEditCommands(nativeKeyBindingsType,
+ DoCommandCallback, mFrame)) {
aEvent->PreventDefault();
}
return NS_OK;
diff --git a/dom/xbl/builtin/ShortcutKeys.cpp b/dom/xbl/builtin/ShortcutKeys.cpp
index 15fc2cfdcb15..138e1d0dd614 100644
--- a/dom/xbl/builtin/ShortcutKeys.cpp
+++ b/dom/xbl/builtin/ShortcutKeys.cpp
@@ -1,6 +1,8 @@
#include "mozilla/ShortcutKeys.h"
#include "../nsXBLPrototypeHandler.h"
#include "nsContentUtils.h"
+#include "nsAtom.h"
+#include "mozilla/TextEvents.h"
namespace mozilla {
@@ -44,6 +46,28 @@ ShortcutKeys::GetHandlers(HandlerType aType)
return sInstance->EnsureHandlers(aType);
}
+/* static */ nsAtom*
+ShortcutKeys::ConvertEventToDOMEventType(const WidgetKeyboardEvent* aWidgetKeyboardEvent)
+{
+ if (aWidgetKeyboardEvent->IsKeyDownOrKeyDownOnPlugin()) {
+ return nsGkAtoms::keydown;
+ }
+ if (aWidgetKeyboardEvent->IsKeyUpOrKeyUpOnPlugin()) {
+ return nsGkAtoms::keyup;
+ }
+ // eAccessKeyNotFound event is always created from eKeyPress event and
+ // the original eKeyPress event has stopped its propagation before dispatched
+ // into the DOM tree in this process and not matched with remote content's
+ // access keys. So, we should treat it as an eKeyPress event and execute
+ // a command if it's registered as a shortcut key.
+ if (aWidgetKeyboardEvent->mMessage == eKeyPress ||
+ aWidgetKeyboardEvent->mMessage == eAccessKeyNotFound) {
+ return nsGkAtoms::keypress;
+ }
+ MOZ_ASSERT_UNREACHABLE("All event messages relating to shortcut keys should be handled");
+ return nullptr;
+}
+
nsXBLPrototypeHandler*
ShortcutKeys::EnsureHandlers(HandlerType aType)
{
diff --git a/dom/xbl/builtin/ShortcutKeys.h b/dom/xbl/builtin/ShortcutKeys.h
index 263cc3b5ff5b..a7bdc88f1923 100644
--- a/dom/xbl/builtin/ShortcutKeys.h
+++ b/dom/xbl/builtin/ShortcutKeys.h
@@ -8,9 +8,12 @@
#include "nsIObserver.h"
class nsXBLPrototypeHandler;
+class nsAtom;
namespace mozilla {
+class WidgetKeyboardEvent;
+
typedef struct
{
const char16_t* event;
@@ -37,6 +40,9 @@ public:
// Returns a pointer to the first handler for the given type.
static nsXBLPrototypeHandler* GetHandlers(HandlerType aType);
+ // Gets the event type for a widget keyboard event.
+ static nsAtom* ConvertEventToDOMEventType(const WidgetKeyboardEvent* aWidgetKeyboardEvent);
+
protected:
ShortcutKeys();
virtual ~ShortcutKeys();
diff --git a/dom/xbl/moz.build b/dom/xbl/moz.build
index a58842f902f7..07c9f4ee26d3 100644
--- a/dom/xbl/moz.build
+++ b/dom/xbl/moz.build
@@ -12,6 +12,7 @@ DIRS += ['builtin']
EXPORTS += [
'nsBindingManager.h',
'nsXBLBinding.h',
+ 'nsXBLPrototypeHandler.h',
'nsXBLService.h',
'nsXBLWindowKeyHandler.h',
]
diff --git a/dom/xbl/nsXBLWindowKeyHandler.cpp b/dom/xbl/nsXBLWindowKeyHandler.cpp
index 78bb17fd9b07..794a3af4a13f 100644
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -137,7 +137,7 @@ nsXBLWindowKeyHandler::EnsureHandlers()
}
nsresult
-nsXBLWindowKeyHandler::WalkHandlers(KeyboardEvent* aKeyEvent, nsAtom* aEventType)
+nsXBLWindowKeyHandler::WalkHandlers(KeyboardEvent* aKeyEvent)
{
if (aKeyEvent->DefaultPrevented()) {
return NS_OK;
@@ -159,7 +159,7 @@ nsXBLWindowKeyHandler::WalkHandlers(KeyboardEvent* aKeyEvent, nsAtom* aEventType
return NS_OK;
}
- WalkHandlersInternal(aKeyEvent, aEventType, true);
+ WalkHandlersInternal(aKeyEvent, true);
return NS_OK;
}
@@ -309,30 +309,6 @@ nsXBLWindowKeyHandler::CollectKeyboardShortcuts()
return KeyboardMap(std::move(shortcuts));
}
-nsAtom*
-nsXBLWindowKeyHandler::ConvertEventToDOMEventType(
- const WidgetKeyboardEvent& aWidgetKeyboardEvent) const
-{
- if (aWidgetKeyboardEvent.IsKeyDownOrKeyDownOnPlugin()) {
- return nsGkAtoms::keydown;
- }
- if (aWidgetKeyboardEvent.IsKeyUpOrKeyUpOnPlugin()) {
- return nsGkAtoms::keyup;
- }
- // eAccessKeyNotFound event is always created from eKeyPress event and
- // the original eKeyPress event has stopped its propagation before dispatched
- // into the DOM tree in this process and not matched with remote content's
- // access keys. So, we should treat it as an eKeyPress event and execute
- // a command if it's registered as a shortcut key.
- if (aWidgetKeyboardEvent.mMessage == eKeyPress ||
- aWidgetKeyboardEvent.mMessage == eAccessKeyNotFound) {
- return nsGkAtoms::keypress;
- }
- MOZ_ASSERT_UNREACHABLE(
- "All event messages which this instance listens to should be handled");
- return nullptr;
-}
-
NS_IMETHODIMP
nsXBLWindowKeyHandler::HandleEvent(Event* aEvent)
{
@@ -380,9 +356,7 @@ nsXBLWindowKeyHandler::HandleEvent(Event* aEvent)
return NS_OK;
}
- RefPtr eventTypeAtom =
- ConvertEventToDOMEventType(*widgetKeyboardEvent);
- return WalkHandlers(keyEvent, eventTypeAtom);
+ return WalkHandlers(keyEvent);
}
void
@@ -490,7 +464,6 @@ nsXBLWindowKeyHandler::IsHTMLEditableFieldFocused()
//
bool
nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent,
- nsAtom* aEventType,
bool aExecute,
bool* aOutReservedForChrome)
{
@@ -502,8 +475,7 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent,
nativeKeyboardEvent->GetShortcutKeyCandidates(shortcutKeys);
if (shortcutKeys.IsEmpty()) {
- return WalkHandlersAndExecute(aKeyEvent, aEventType,
- 0, IgnoreModifierState(),
+ return WalkHandlersAndExecute(aKeyEvent, 0, IgnoreModifierState(),
aExecute, aOutReservedForChrome);
}
@@ -511,8 +483,7 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent,
ShortcutKeyCandidate& key = shortcutKeys[i];
IgnoreModifierState ignoreModifierState;
ignoreModifierState.mShift = key.mIgnoreShift;
- if (WalkHandlersAndExecute(aKeyEvent, aEventType,
- key.mCharCode, ignoreModifierState,
+ if (WalkHandlersAndExecute(aKeyEvent, key.mCharCode, ignoreModifierState,
aExecute, aOutReservedForChrome)) {
return true;
}
@@ -523,7 +494,6 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent,
bool
nsXBLWindowKeyHandler::WalkHandlersAndExecute(
KeyboardEvent* aKeyEvent,
- nsAtom* aEventType,
uint32_t aCharCode,
const IgnoreModifierState& aIgnoreModifierState,
bool aExecute,
@@ -539,6 +509,8 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(
return false;
}
+ nsAtom* eventType = ShortcutKeys::ConvertEventToDOMEventType(widgetKeyboardEvent);
+
// Try all of the handlers until we find one that matches the event.
for (nsXBLPrototypeHandler* handler = mHandler;
handler;
@@ -560,7 +532,7 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(
}
// The other event types should exactly be matched with the handler's
// event type.
- } else if (!handler->EventTypeEquals(aEventType)) {
+ } else if (!handler->EventTypeEquals(eventType)) {
continue;
}
} else {
@@ -571,12 +543,12 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(
// prevented, following keypress event won't be fired. However, if
// following keypress event is reserved, we shouldn't allow web
// contents to prevent the default of the preceding keydown event.
- if (aEventType != nsGkAtoms::keydown &&
- aEventType != nsGkAtoms::keypress) {
+ if (eventType != nsGkAtoms::keydown &&
+ eventType != nsGkAtoms::keypress) {
continue;
}
- } else if (!handler->EventTypeEquals(aEventType)) {
- // Otherwise, aEventType should exactly be matched.
+ } else if (!handler->EventTypeEquals(eventType)) {
+ // Otherwise, eventType should exactly be matched.
continue;
}
}
@@ -601,7 +573,7 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(
}
if (!aExecute) {
- if (handler->EventTypeEquals(aEventType)) {
+ if (handler->EventTypeEquals(eventType)) {
if (aOutReservedForChrome) {
*aOutReservedForChrome = IsReservedKey(widgetKeyboardEvent, handler);
}
@@ -612,7 +584,7 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(
// If the command is reserved and the event is keydown, check also if
// the handler is for keypress because if following keypress event is
// reserved, we shouldn't dispatch the event into web contents.
- if (aEventType == nsGkAtoms::keydown &&
+ if (eventType == nsGkAtoms::keydown &&
handler->EventTypeEquals(nsGkAtoms::keypress)) {
if (IsReservedKey(widgetKeyboardEvent, handler)) {
if (aOutReservedForChrome) {
@@ -661,8 +633,8 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(
if (!aIgnoreModifierState.mOS && widgetKeyboardEvent->IsOS()) {
IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
ignoreModifierState.mOS = true;
- return WalkHandlersAndExecute(aKeyEvent, aEventType,
- aCharCode, ignoreModifierState, aExecute);
+ return WalkHandlersAndExecute(aKeyEvent, aCharCode, ignoreModifierState,
+ aExecute);
}
#endif
@@ -707,10 +679,7 @@ nsXBLWindowKeyHandler::HasHandlerForEvent(KeyboardEvent* aEvent,
return false;
}
- RefPtr eventTypeAtom =
- ConvertEventToDOMEventType(*widgetKeyboardEvent);
- return WalkHandlersInternal(aEvent, eventTypeAtom, false,
- aOutReservedForChrome);
+ return WalkHandlersInternal(aEvent, false, aOutReservedForChrome);
}
already_AddRefed
diff --git a/dom/xbl/nsXBLWindowKeyHandler.h b/dom/xbl/nsXBLWindowKeyHandler.h
index 135dd034ee58..f38b049f90ea 100644
--- a/dom/xbl/nsXBLWindowKeyHandler.h
+++ b/dom/xbl/nsXBLWindowKeyHandler.h
@@ -50,17 +50,16 @@ public:
protected:
virtual ~nsXBLWindowKeyHandler();
- nsresult WalkHandlers(KeyboardEvent* aKeyEvent, nsAtom* aEventType);
+ nsresult WalkHandlers(KeyboardEvent* aKeyEvent);
// walk the handlers, looking for one to handle the event
bool WalkHandlersInternal(KeyboardEvent* aKeyEvent,
- nsAtom* aEventType,
bool aExecute,
bool* aOutReservedForChrome = nullptr);
// walk the handlers for aEvent, aCharCode and aIgnoreModifierState. Execute
// it if aExecute = true.
- bool WalkHandlersAndExecute(KeyboardEvent* aKeyEvent, nsAtom* aEventType,
+ bool WalkHandlersAndExecute(KeyboardEvent* aKeyEvent,
uint32_t aCharCode,
const IgnoreModifierState& aIgnoreModifierState,
bool aExecute,
@@ -82,12 +81,6 @@ protected:
bool IsReservedKey(mozilla::WidgetKeyboardEvent* aKeyEvent,
nsXBLPrototypeHandler* aHandler);
- // Returns event type for matching between aWidgetKeyboardEvent and
- // shortcut key handlers. This is used for calling WalkHandlers(),
- // WalkHandlersInternal() and WalkHandlersAndExecute().
- nsAtom* ConvertEventToDOMEventType(
- const mozilla::WidgetKeyboardEvent& aWidgetKeyboardEvent) const;
-
// lazily load the handlers. Overridden to handle being attached
// to a particular element rather than the document
nsresult EnsureHandlers();
diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css
index 7b44e708415c..a49bec4971c3 100644
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -102,7 +102,6 @@ input {
word-spacing: normal;
letter-spacing: normal;
cursor: text;
- -moz-binding: url("chrome://global/content/platformHTMLBindings.xml#inputFields");
text-indent: 0;
-moz-user-select: text;
text-shadow: none;
@@ -134,7 +133,6 @@ textarea {
vertical-align: text-bottom;
cursor: text;
resize: both;
- -moz-binding: url("chrome://global/content/platformHTMLBindings.xml#textAreas");
-moz-appearance: textfield-multiline;
text-indent: 0;
-moz-user-select: text;
@@ -448,7 +446,6 @@ input[type="hidden"] {
border: 0;
cursor: auto;
-moz-user-focus: ignore;
- -moz-binding: none;
}
/* image buttons */
@@ -460,7 +457,6 @@ input[type="image"] {
font-family: sans-serif;
font-size: small;
cursor: pointer;
- -moz-binding: none;
}
input[type="image"]:disabled {
@@ -482,7 +478,6 @@ input[type="file"] {
/* Revert rules which apply on all inputs. */
-moz-appearance: none;
- -moz-binding: none;
cursor: default;
border: none;
@@ -552,7 +547,6 @@ input[type="checkbox"] {
cursor: default;
/* unset some values from the general 'input' rule above: */
padding: unset;
- -moz-binding: unset;
border: unset;
background-color: unset;
color: unset;
@@ -608,7 +602,6 @@ input[type="submit"] {
cursor: default;
box-sizing: border-box;
-moz-user-select: none;
- -moz-binding: none;
}
/* Text-related properties for buttons: these ones are not shared with
@@ -893,7 +886,6 @@ input[type=range] {
cursor: default;
background: none;
border: none;
- -moz-binding: none; /* we don't want any of platformHTMLBindings.xml#inputFields */
/* Prevent nsFrame::HandlePress setting mouse capture to this element. */
-moz-user-select: none ! important;
}
@@ -1015,7 +1007,6 @@ input[type=range]::-moz-range-thumb {
input[type="number"] {
-moz-appearance: number-input;
/* Has to revert some properties applied by the generic input rule. */
- -moz-binding: none;
inline-size: 20ch; /* It'd be nice if this matched the default inline-size
of , but that's not easy to achieve
due to platform differences. */