Bug 1735754 [wpt PR 31232] - Make the higher-order comparisons in the structured...
[gecko.git] / widget / TextEvents.h
blobd505cf28c2f8018be318b6e4b6d2e59edc731536
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_TextEvents_h__
7 #define mozilla_TextEvents_h__
9 #include <stdint.h>
11 #include "mozilla/Assertions.h"
12 #include "mozilla/BasicEvents.h"
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/EventForwards.h" // for KeyNameIndex, temporarily
15 #include "mozilla/FontRange.h"
16 #include "mozilla/Maybe.h"
17 #include "mozilla/OwningNonNull.h"
18 #include "mozilla/TextRange.h"
19 #include "mozilla/WritingModes.h"
20 #include "mozilla/dom/DataTransfer.h"
21 #include "mozilla/dom/KeyboardEventBinding.h"
22 #include "mozilla/dom/StaticRange.h"
23 #include "mozilla/widget/IMEData.h"
24 #include "nsCOMPtr.h"
25 #include "nsHashtablesFwd.h"
26 #include "nsISelectionListener.h"
27 #include "nsITransferable.h"
28 #include "nsRect.h"
29 #include "nsString.h"
30 #include "nsTArray.h"
32 class nsStringHashKey;
34 /******************************************************************************
35 * virtual keycode values
36 ******************************************************************************/
38 enum {
39 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode,
40 #include "mozilla/VirtualKeyCodeList.h"
41 #undef NS_DEFINE_VK
42 NS_VK_UNKNOWN = 0xFF
45 namespace mozilla {
47 enum : uint32_t {
48 eKeyLocationStandard = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_STANDARD,
49 eKeyLocationLeft = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_LEFT,
50 eKeyLocationRight = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_RIGHT,
51 eKeyLocationNumpad = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_NUMPAD
54 const nsCString GetDOMKeyCodeName(uint32_t aKeyCode);
56 namespace dom {
57 class PBrowserParent;
58 class PBrowserChild;
59 } // namespace dom
60 namespace plugins {
61 class PPluginInstanceChild;
62 } // namespace plugins
64 enum class AccessKeyType {
65 // Handle access key for chrome.
66 eChrome,
67 // Handle access key for content.
68 eContent,
69 // Don't handle access key.
70 eNone
73 /******************************************************************************
74 * mozilla::AlternativeCharCode
76 * This stores alternative charCode values of a key event with some modifiers.
77 * The stored values proper for testing shortcut key or access key.
78 ******************************************************************************/
80 struct AlternativeCharCode {
81 AlternativeCharCode() : mUnshiftedCharCode(0), mShiftedCharCode(0) {}
82 AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode)
83 : mUnshiftedCharCode(aUnshiftedCharCode),
84 mShiftedCharCode(aShiftedCharCode) {}
85 uint32_t mUnshiftedCharCode;
86 uint32_t mShiftedCharCode;
89 /******************************************************************************
90 * mozilla::ShortcutKeyCandidate
92 * This stores a candidate of shortcut key combination.
93 ******************************************************************************/
95 struct ShortcutKeyCandidate {
96 ShortcutKeyCandidate() : mCharCode(0), mIgnoreShift(0) {}
97 ShortcutKeyCandidate(uint32_t aCharCode, bool aIgnoreShift)
98 : mCharCode(aCharCode), mIgnoreShift(aIgnoreShift) {}
99 // The mCharCode value which must match keyboard shortcut definition.
100 uint32_t mCharCode;
101 // true if Shift state can be ignored. Otherwise, Shift key state must
102 // match keyboard shortcut definition.
103 bool mIgnoreShift;
106 /******************************************************************************
107 * mozilla::IgnoreModifierState
109 * This stores flags for modifiers that should be ignored when matching
110 * XBL handlers.
111 ******************************************************************************/
113 struct IgnoreModifierState {
114 // When mShift is true, Shift key state will be ignored.
115 bool mShift;
116 // When mOS is true, OS key state will be ignored.
117 bool mOS;
119 IgnoreModifierState() : mShift(false), mOS(false) {}
122 /******************************************************************************
123 * mozilla::WidgetKeyboardEvent
124 ******************************************************************************/
126 class WidgetKeyboardEvent : public WidgetInputEvent {
127 private:
128 friend class dom::PBrowserParent;
129 friend class dom::PBrowserChild;
130 friend struct IPC::ParamTraits<WidgetKeyboardEvent>;
132 protected:
133 WidgetKeyboardEvent()
134 : mNativeKeyEvent(nullptr),
135 mKeyCode(0),
136 mCharCode(0),
137 mPseudoCharCode(0),
138 mLocation(eKeyLocationStandard),
139 mUniqueId(0),
140 mKeyNameIndex(KEY_NAME_INDEX_Unidentified),
141 mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN),
142 mIsRepeat(false),
143 mIsComposing(false),
144 mIsSynthesizedByTIP(false),
145 mMaybeSkippableInRemoteProcess(true),
146 mUseLegacyKeyCodeAndCharCodeValues(false),
147 mEditCommandsForSingleLineEditorInitialized(false),
148 mEditCommandsForMultiLineEditorInitialized(false),
149 mEditCommandsForRichTextEditorInitialized(false) {}
151 public:
152 virtual WidgetKeyboardEvent* AsKeyboardEvent() override { return this; }
154 WidgetKeyboardEvent(bool aIsTrusted, EventMessage aMessage,
155 nsIWidget* aWidget,
156 EventClassID aEventClassID = eKeyboardEventClass)
157 : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID),
158 mNativeKeyEvent(nullptr),
159 mKeyCode(0),
160 mCharCode(0),
161 mPseudoCharCode(0),
162 mLocation(eKeyLocationStandard),
163 mUniqueId(0),
164 mKeyNameIndex(KEY_NAME_INDEX_Unidentified),
165 mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN),
166 mIsRepeat(false),
167 mIsComposing(false),
168 mIsSynthesizedByTIP(false),
169 mMaybeSkippableInRemoteProcess(true),
170 mUseLegacyKeyCodeAndCharCodeValues(false),
171 mEditCommandsForSingleLineEditorInitialized(false),
172 mEditCommandsForMultiLineEditorInitialized(false),
173 mEditCommandsForRichTextEditorInitialized(false) {}
175 // IsInputtingText() and IsInputtingLineBreak() are used to check if
176 // it should cause eKeyPress events even on web content.
177 // UI Events defines that "keypress" event should be fired "if and only if
178 // that key normally produces a character value".
179 // <https://www.w3.org/TR/uievents/#event-type-keypress>
180 // Additionally, for backward compatiblity with all existing browsers,
181 // there is a spec issue for Enter key press.
182 // <https://github.com/w3c/uievents/issues/183>
183 bool IsInputtingText() const {
184 // NOTE: On some keyboard layout, some characters are inputted with Control
185 // key or Alt key, but at that time, widget clears the modifier flag
186 // from eKeyPress event because our TextEditor won't handle eKeyPress
187 // events as inputting text (bug 1346832).
188 // NOTE: There are some complicated issues of our traditional behavior.
189 // -- On Windows, KeyboardLayout::WillDispatchKeyboardEvent() clears
190 // MODIFIER_ALT and MODIFIER_CONTROL of eKeyPress event if it
191 // should be treated as inputting a character because AltGr is
192 // represented with both Alt key and Ctrl key are pressed, and
193 // some keyboard layouts may produces a character with Ctrl key.
194 // -- On Linux, KeymapWrapper doesn't have this hack since perhaps,
195 // we don't have any bug reports that user cannot input proper
196 // character with Alt and/or Ctrl key.
197 // -- On macOS, IMEInputHandler::WillDispatchKeyboardEvent() clears
198 // MODIFIER_ALT and MDOFIEIR_CONTROL of eKeyPress event only when
199 // TextInputHandler::InsertText() has been called for the event.
200 // I.e., they are cleared only when an editor has focus (even if IME
201 // is disabled in password field or by |ime-mode: disabled;|) because
202 // TextInputHandler::InsertText() is called while
203 // TextInputHandler::HandleKeyDownEvent() calls interpretKeyEvents:
204 // to notify text input processor of Cocoa (including IME). In other
205 // words, when we need to disable IME completey when no editor has
206 // focus, we cannot call interpretKeyEvents:. So,
207 // TextInputHandler::InsertText() won't be called when no editor has
208 // focus so that neither MODIFIER_ALT nor MODIFIER_CONTROL is
209 // cleared. So, fortunately, altKey and ctrlKey values of "keypress"
210 // events are same as the other browsers only when no editor has
211 // focus.
212 // NOTE: As mentioned above, for compatibility with the other browsers on
213 // macOS, we should keep MODIFIER_ALT and MODIFIER_CONTROL flags of
214 // eKeyPress events when no editor has focus. However, Alt key,
215 // labeled "option" on keyboard for Mac, is AltGraph key on the other
216 // platforms. So, even if MODIFIER_ALT is set, we need to dispatch
217 // eKeyPress event even on web content unless mCharCode is 0.
218 // Therefore, we need to ignore MODIFIER_ALT flag here only on macOS.
219 return mMessage == eKeyPress && mCharCode &&
220 !(mModifiers & (
221 #ifndef XP_MACOSX
222 // So, ignore MODIFIER_ALT only on macOS since
223 // option key is used as AltGraph key on macOS.
224 MODIFIER_ALT |
225 #endif // #ifndef XP_MAXOSX
226 MODIFIER_CONTROL | MODIFIER_META | MODIFIER_OS));
229 bool IsInputtingLineBreak() const {
230 return mMessage == eKeyPress && mKeyNameIndex == KEY_NAME_INDEX_Enter &&
231 !(mModifiers &
232 (MODIFIER_ALT | MODIFIER_CONTROL | MODIFIER_META | MODIFIER_OS));
236 * ShouldKeyPressEventBeFiredOnContent() should be called only when the
237 * instance is eKeyPress event. This returns true when the eKeyPress
238 * event should be fired even on content in the default event group.
240 bool ShouldKeyPressEventBeFiredOnContent() const {
241 MOZ_DIAGNOSTIC_ASSERT(mMessage == eKeyPress);
242 if (IsInputtingText() || IsInputtingLineBreak()) {
243 return true;
245 // Ctrl + Enter won't cause actual input in our editor.
246 // However, the other browsers fire keypress event in any platforms.
247 // So, for compatibility with them, we should fire keypress event for
248 // Ctrl + Enter too.
249 return mMessage == eKeyPress && mKeyNameIndex == KEY_NAME_INDEX_Enter &&
250 !(mModifiers &
251 (MODIFIER_ALT | MODIFIER_META | MODIFIER_OS | MODIFIER_SHIFT));
254 virtual WidgetEvent* Duplicate() const override {
255 MOZ_ASSERT(mClass == eKeyboardEventClass,
256 "Duplicate() must be overridden by sub class");
257 // Not copying widget, it is a weak reference.
258 WidgetKeyboardEvent* result =
259 new WidgetKeyboardEvent(false, mMessage, nullptr);
260 result->AssignKeyEventData(*this, true);
261 result->mEditCommandsForSingleLineEditor =
262 mEditCommandsForSingleLineEditor.Clone();
263 result->mEditCommandsForMultiLineEditor =
264 mEditCommandsForMultiLineEditor.Clone();
265 result->mEditCommandsForRichTextEditor =
266 mEditCommandsForRichTextEditor.Clone();
267 result->mFlags = mFlags;
268 return result;
271 bool CanUserGestureActivateTarget() const {
272 // Printable keys, 'carriage return' and 'space' are supported user gestures
273 // for activating the document. However, if supported key is being pressed
274 // combining with other operation keys, such like alt, control ..etc., we
275 // won't activate the target for them because at that time user might
276 // interact with browser or window manager which doesn't necessarily
277 // demonstrate user's intent to play media.
278 const bool isCombiningWithOperationKeys = (IsControl() && !IsAltGraph()) ||
279 (IsAlt() && !IsAltGraph()) ||
280 IsMeta() || IsOS();
281 const bool isEnterOrSpaceKey =
282 mKeyNameIndex == KEY_NAME_INDEX_Enter || mKeyCode == NS_VK_SPACE;
283 return (PseudoCharCode() || isEnterOrSpaceKey) &&
284 (!isCombiningWithOperationKeys ||
285 // ctrl-c/ctrl-x/ctrl-v is quite common shortcut for clipboard
286 // operation.
287 // XXXedgar, we have to find a better way to handle browser keyboard
288 // shortcut for user activation, instead of just ignoring all
289 // combinations, see bug 1641171.
290 ((mKeyCode == dom::KeyboardEvent_Binding::DOM_VK_C ||
291 mKeyCode == dom::KeyboardEvent_Binding::DOM_VK_V ||
292 mKeyCode == dom::KeyboardEvent_Binding::DOM_VK_X) &&
293 IsAccel()));
297 * CanTreatAsUserInput() returns true if the key is pressed for perhaps
298 * doing something on the web app or our UI. This means that when this
299 * returns false, e.g., when user presses a modifier key, user is probably
300 * displeased by opening popup, entering fullscreen mode, etc. Therefore,
301 * only when this returns true, such reactions should be allowed.
303 bool CanTreatAsUserInput() const {
304 if (!IsTrusted()) {
305 return false;
307 switch (mKeyNameIndex) {
308 case KEY_NAME_INDEX_Escape:
309 // modifier keys:
310 case KEY_NAME_INDEX_Alt:
311 case KEY_NAME_INDEX_AltGraph:
312 case KEY_NAME_INDEX_CapsLock:
313 case KEY_NAME_INDEX_Control:
314 case KEY_NAME_INDEX_Fn:
315 case KEY_NAME_INDEX_FnLock:
316 case KEY_NAME_INDEX_Meta:
317 case KEY_NAME_INDEX_NumLock:
318 case KEY_NAME_INDEX_ScrollLock:
319 case KEY_NAME_INDEX_Shift:
320 case KEY_NAME_INDEX_Symbol:
321 case KEY_NAME_INDEX_SymbolLock:
322 // legacy modifier keys:
323 case KEY_NAME_INDEX_Hyper:
324 case KEY_NAME_INDEX_Super:
325 // obsolete modifier key:
326 case KEY_NAME_INDEX_OS:
327 return false;
328 default:
329 return true;
334 * ShouldInteractionTimeRecorded() returns true if the handling time of
335 * the event should be recorded with the telemetry.
337 bool ShouldInteractionTimeRecorded() const {
338 // Let's record only when we can treat the instance is a user input.
339 return CanTreatAsUserInput();
342 // OS translated Unicode chars which are used for accesskey and accelkey
343 // handling. The handlers will try from first character to last character.
344 CopyableTArray<AlternativeCharCode> mAlternativeCharCodes;
345 // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING.
346 nsString mKeyValue;
347 // DOM KeyboardEvent.code only when mCodeNameIndex is
348 // CODE_NAME_INDEX_USE_STRING.
349 nsString mCodeValue;
351 // OS-specific native event can optionally be preserved.
352 // This is used to retrieve editing shortcut keys in the environment.
353 void* mNativeKeyEvent;
354 // A DOM keyCode value or 0. If a keypress event whose mCharCode is 0, this
355 // should be 0.
356 uint32_t mKeyCode;
357 // If the instance is a keypress event of a printable key, this is a UTF-16
358 // value of the key. Otherwise, 0. This value must not be a control
359 // character when some modifiers are active. Then, this value should be an
360 // unmodified value except Shift and AltGr.
361 uint32_t mCharCode;
362 // mPseudoCharCode is valid only when mMessage is an eKeyDown event.
363 // This stores mCharCode value of keypress event which is fired with same
364 // key value and same modifier state.
365 uint32_t mPseudoCharCode;
366 // One of eKeyLocation*
367 uint32_t mLocation;
368 // Unique id associated with a keydown / keypress event. It's ok if this wraps
369 // over long periods.
370 uint32_t mUniqueId;
372 // DOM KeyboardEvent.key
373 KeyNameIndex mKeyNameIndex;
374 // DOM KeyboardEvent.code
375 CodeNameIndex mCodeNameIndex;
377 // Indicates whether the event is generated by auto repeat or not.
378 // if this is keyup event, always false.
379 bool mIsRepeat;
380 // Indicates whether the event is generated during IME (or deadkey)
381 // composition. This is initialized by EventStateManager. So, key event
382 // dispatchers don't need to initialize this.
383 bool mIsComposing;
384 // Indicates whether the event is synthesized from Text Input Processor
385 // or an actual event from nsAppShell.
386 bool mIsSynthesizedByTIP;
387 // Indicates whether the event is skippable in remote process.
388 // Don't refer this member directly when you need to check this.
389 // Use CanSkipInRemoteProcess() instead.
390 bool mMaybeSkippableInRemoteProcess;
391 // Indicates whether the event should return legacy keyCode value and
392 // charCode value to web apps (one of them is always 0) or not, when it's
393 // an eKeyPress event.
394 bool mUseLegacyKeyCodeAndCharCodeValues;
396 bool CanSkipInRemoteProcess() const {
397 // If this is a repeat event (i.e., generated by auto-repeat feature of
398 // the platform), remove process may skip to handle it because of
399 // performances reasons.. However, if it's caused by odd keyboard utils,
400 // we should not ignore any key events even marked as repeated since
401 // generated key sequence may be important to input proper text. E.g.,
402 // "SinhalaTamil IME" on Windows emulates dead key like input with
403 // generating WM_KEYDOWN for VK_PACKET (inputting any Unicode characters
404 // without keyboard layout information) and VK_BACK (Backspace) to remove
405 // previous character(s) and those messages may be marked as "repeat" by
406 // their bug.
407 return mIsRepeat && mMaybeSkippableInRemoteProcess;
411 * If the key is an arrow key, and the current selection is in a vertical
412 * content, the caret should be moved to physically. However, arrow keys
413 * are mapped to logical move commands in horizontal content. Therefore,
414 * we need to check writing mode if and only if the key is an arrow key, and
415 * need to remap the command to logical command in vertical content if the
416 * writing mode at selection is vertical. These methods help to convert
417 * arrow keys in horizontal content to correspnding direction arrow keys
418 * in vertical content.
420 bool NeedsToRemapNavigationKey() const {
421 // TODO: Use mKeyNameIndex instead.
422 return mKeyCode >= NS_VK_LEFT && mKeyCode <= NS_VK_DOWN;
425 uint32_t GetRemappedKeyCode(const WritingMode& aWritingMode) const {
426 if (!aWritingMode.IsVertical()) {
427 return mKeyCode;
429 switch (mKeyCode) {
430 case NS_VK_LEFT:
431 return aWritingMode.IsVerticalLR() ? NS_VK_UP : NS_VK_DOWN;
432 case NS_VK_RIGHT:
433 return aWritingMode.IsVerticalLR() ? NS_VK_DOWN : NS_VK_UP;
434 case NS_VK_UP:
435 return NS_VK_LEFT;
436 case NS_VK_DOWN:
437 return NS_VK_RIGHT;
438 default:
439 return mKeyCode;
443 KeyNameIndex GetRemappedKeyNameIndex(const WritingMode& aWritingMode) const {
444 if (!aWritingMode.IsVertical()) {
445 return mKeyNameIndex;
447 uint32_t remappedKeyCode = GetRemappedKeyCode(aWritingMode);
448 if (remappedKeyCode == mKeyCode) {
449 return mKeyNameIndex;
451 switch (remappedKeyCode) {
452 case NS_VK_LEFT:
453 return KEY_NAME_INDEX_ArrowLeft;
454 case NS_VK_RIGHT:
455 return KEY_NAME_INDEX_ArrowRight;
456 case NS_VK_UP:
457 return KEY_NAME_INDEX_ArrowUp;
458 case NS_VK_DOWN:
459 return KEY_NAME_INDEX_ArrowDown;
460 default:
461 MOZ_ASSERT_UNREACHABLE("Add a case for the new remapped key");
462 return mKeyNameIndex;
467 * Retrieves all edit commands from mWidget. This shouldn't be called when
468 * the instance is an untrusted event, doesn't have widget or in non-chrome
469 * process.
471 * @param aWritingMode
472 * When writing mode of focused element is vertical, this
473 * will resolve some key's physical direction to logical
474 * direction. For doing it, this must be set to the
475 * writing mode at current selection. However, when there
476 * is no focused element and no selection ranges, this
477 * should be set to Nothing(). Using the result of
478 * `TextEventDispatcher::MaybeWritingModeAtSelection()` is
479 * recommended.
481 MOZ_CAN_RUN_SCRIPT void InitAllEditCommands(
482 const Maybe<WritingMode>& aWritingMode);
485 * Retrieves edit commands from mWidget only for aType. This shouldn't be
486 * called when the instance is an untrusted event or doesn't have widget.
488 * @param aWritingMode
489 * When writing mode of focused element is vertical, this
490 * will resolve some key's physical direction to logical
491 * direction. For doing it, this must be set to the
492 * writing mode at current selection. However, when there
493 * is no focused element and no selection ranges, this
494 * should be set to Nothing(). Using the result of
495 * `TextEventDispatcher::MaybeWritingModeAtSelection()` is
496 * recommended.
497 * @return false if some resource is not available to get
498 * commands unexpectedly. Otherwise, true even if
499 * retrieved command is nothing.
501 MOZ_CAN_RUN_SCRIPT bool InitEditCommandsFor(
502 nsIWidget::NativeKeyBindingsType aType,
503 const Maybe<WritingMode>& aWritingMode);
506 * PreventNativeKeyBindings() makes the instance to not cause any edit
507 * actions even if it matches with a native key binding.
509 void PreventNativeKeyBindings() {
510 mEditCommandsForSingleLineEditor.Clear();
511 mEditCommandsForMultiLineEditor.Clear();
512 mEditCommandsForRichTextEditor.Clear();
513 mEditCommandsForSingleLineEditorInitialized = true;
514 mEditCommandsForMultiLineEditorInitialized = true;
515 mEditCommandsForRichTextEditorInitialized = true;
519 * EditCommandsConstRef() returns reference to edit commands for aType.
521 const nsTArray<CommandInt>& EditCommandsConstRef(
522 nsIWidget::NativeKeyBindingsType aType) const {
523 return const_cast<WidgetKeyboardEvent*>(this)->EditCommandsRef(aType);
527 * IsEditCommandsInitialized() returns true if edit commands for aType
528 * was already initialized. Otherwise, false.
530 bool IsEditCommandsInitialized(nsIWidget::NativeKeyBindingsType aType) const {
531 return const_cast<WidgetKeyboardEvent*>(this)->IsEditCommandsInitializedRef(
532 aType);
536 * AreAllEditCommandsInitialized() returns true if edit commands for all
537 * types were already initialized. Otherwise, false.
539 bool AreAllEditCommandsInitialized() const {
540 return mEditCommandsForSingleLineEditorInitialized &&
541 mEditCommandsForMultiLineEditorInitialized &&
542 mEditCommandsForRichTextEditorInitialized;
546 * Execute edit commands for aType.
548 * @return true if the caller should do nothing anymore.
549 * false, otherwise.
551 typedef void (*DoCommandCallback)(Command, void*);
552 MOZ_CAN_RUN_SCRIPT bool ExecuteEditCommands(
553 nsIWidget::NativeKeyBindingsType aType, DoCommandCallback aCallback,
554 void* aCallbackData);
556 // If the key should cause keypress events, this returns true.
557 // Otherwise, false.
558 bool ShouldCauseKeypressEvents() const;
560 // mCharCode value of non-eKeyPress events is always 0. However, if
561 // non-eKeyPress event has one or more alternative char code values,
562 // its first item should be the mCharCode value of following eKeyPress event.
563 // PseudoCharCode() returns mCharCode value for eKeyPress event,
564 // the first alternative char code value of non-eKeyPress event or 0.
565 uint32_t PseudoCharCode() const {
566 return mMessage == eKeyPress ? mCharCode : mPseudoCharCode;
568 void SetCharCode(uint32_t aCharCode) {
569 if (mMessage == eKeyPress) {
570 mCharCode = aCharCode;
571 } else {
572 mPseudoCharCode = aCharCode;
576 void GetDOMKeyName(nsAString& aKeyName) {
577 if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
578 aKeyName = mKeyValue;
579 return;
581 GetDOMKeyName(mKeyNameIndex, aKeyName);
583 void GetDOMCodeName(nsAString& aCodeName) {
584 if (mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
585 aCodeName = mCodeValue;
586 return;
588 GetDOMCodeName(mCodeNameIndex, aCodeName);
592 * GetFallbackKeyCodeOfPunctuationKey() returns a DOM keyCode value for
593 * aCodeNameIndex. This is keyCode value of the key when active keyboard
594 * layout is ANSI (US), JIS or ABNT keyboard layout (the latter 2 layouts
595 * are used only when ANSI doesn't have the key). The result is useful
596 * if the key doesn't produce ASCII character with active keyboard layout
597 * nor with alternative ASCII capable keyboard layout.
599 static uint32_t GetFallbackKeyCodeOfPunctuationKey(
600 CodeNameIndex aCodeNameIndex);
602 bool IsModifierKeyEvent() const {
603 return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE;
607 * Get the candidates for shortcut key.
609 * @param aCandidates [out] the candidate shortcut key combination list.
610 * the first item is most preferred.
612 void GetShortcutKeyCandidates(ShortcutKeyCandidateArray& aCandidates) const;
615 * Get the candidates for access key.
617 * @param aCandidates [out] the candidate access key list.
618 * the first item is most preferred.
620 void GetAccessKeyCandidates(nsTArray<uint32_t>& aCandidates) const;
623 * Check whether the modifiers match with chrome access key or
624 * content access key.
626 bool ModifiersMatchWithAccessKey(AccessKeyType aType) const;
629 * Return active modifiers which may match with access key.
630 * For example, even if Alt is access key modifier, then, when Control,
631 * CapseLock and NumLock are active, this returns only MODIFIER_CONTROL.
633 Modifiers ModifiersForAccessKeyMatching() const;
636 * Return access key modifiers.
638 static Modifiers AccessKeyModifiers(AccessKeyType aType);
640 static void Shutdown();
643 * ComputeLocationFromCodeValue() returns one of .mLocation value
644 * (eKeyLocation*) which is the most preferred value for the specified code
645 * value.
647 static uint32_t ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex);
650 * ComputeKeyCodeFromKeyNameIndex() return a .mKeyCode value which can be
651 * mapped from the specified key value. Note that this returns 0 if the
652 * key name index is KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING.
653 * This means that this method is useful only for non-printable keys.
655 static uint32_t ComputeKeyCodeFromKeyNameIndex(KeyNameIndex aKeyNameIndex);
658 * ComputeCodeNameIndexFromKeyNameIndex() returns a code name index which
659 * is typically mapped to given key name index on the platform.
660 * Note that this returns CODE_NAME_INDEX_UNKNOWN if the key name index is
661 * KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING.
662 * This means that this method is useful only for non-printable keys.
664 * @param aKeyNameIndex A non-printable key name index.
665 * @param aLocation Should be one of location value. This is
666 * important when aKeyNameIndex may exist in
667 * both Numpad or Standard, or in both Left or
668 * Right. If this is nothing, this method
669 * returns Left or Standard position's code
670 * value.
672 static CodeNameIndex ComputeCodeNameIndexFromKeyNameIndex(
673 KeyNameIndex aKeyNameIndex, const Maybe<uint32_t>& aLocation);
676 * GetModifierForKeyName() returns a value of Modifier which is activated
677 * by the aKeyNameIndex.
679 static Modifier GetModifierForKeyName(KeyNameIndex aKeyNameIndex);
682 * IsLeftOrRightModiferKeyNameIndex() returns true if aKeyNameIndex is a
683 * modifier key which may be in Left and Right location.
685 static bool IsLeftOrRightModiferKeyNameIndex(KeyNameIndex aKeyNameIndex) {
686 switch (aKeyNameIndex) {
687 case KEY_NAME_INDEX_Alt:
688 case KEY_NAME_INDEX_Control:
689 case KEY_NAME_INDEX_Meta:
690 case KEY_NAME_INDEX_OS:
691 case KEY_NAME_INDEX_Shift:
692 return true;
693 default:
694 return false;
699 * IsLockableModifier() returns true if aKeyNameIndex is a lockable modifier
700 * key such as CapsLock and NumLock.
702 static bool IsLockableModifier(KeyNameIndex aKeyNameIndex);
704 static void GetDOMKeyName(KeyNameIndex aKeyNameIndex, nsAString& aKeyName);
705 static void GetDOMCodeName(CodeNameIndex aCodeNameIndex,
706 nsAString& aCodeName);
708 static KeyNameIndex GetKeyNameIndex(const nsAString& aKeyValue);
709 static CodeNameIndex GetCodeNameIndex(const nsAString& aCodeValue);
711 static const char* GetCommandStr(Command aCommand);
713 void AssignKeyEventData(const WidgetKeyboardEvent& aEvent,
714 bool aCopyTargets) {
715 AssignInputEventData(aEvent, aCopyTargets);
717 mKeyCode = aEvent.mKeyCode;
718 mCharCode = aEvent.mCharCode;
719 mPseudoCharCode = aEvent.mPseudoCharCode;
720 mLocation = aEvent.mLocation;
721 mAlternativeCharCodes = aEvent.mAlternativeCharCodes.Clone();
722 mIsRepeat = aEvent.mIsRepeat;
723 mIsComposing = aEvent.mIsComposing;
724 mKeyNameIndex = aEvent.mKeyNameIndex;
725 mCodeNameIndex = aEvent.mCodeNameIndex;
726 mKeyValue = aEvent.mKeyValue;
727 mCodeValue = aEvent.mCodeValue;
728 // Don't copy mNativeKeyEvent because it may be referred after its instance
729 // is destroyed.
730 mNativeKeyEvent = nullptr;
731 mUniqueId = aEvent.mUniqueId;
732 mIsSynthesizedByTIP = aEvent.mIsSynthesizedByTIP;
733 mMaybeSkippableInRemoteProcess = aEvent.mMaybeSkippableInRemoteProcess;
734 mUseLegacyKeyCodeAndCharCodeValues =
735 aEvent.mUseLegacyKeyCodeAndCharCodeValues;
737 // Don't copy mEditCommandsFor*Editor because it may require a lot of
738 // memory space. For example, if the event is dispatched but grabbed by
739 // a JS variable, they are not necessary anymore.
741 mEditCommandsForSingleLineEditorInitialized =
742 aEvent.mEditCommandsForSingleLineEditorInitialized;
743 mEditCommandsForMultiLineEditorInitialized =
744 aEvent.mEditCommandsForMultiLineEditorInitialized;
745 mEditCommandsForRichTextEditorInitialized =
746 aEvent.mEditCommandsForRichTextEditorInitialized;
749 void AssignCommands(const WidgetKeyboardEvent& aEvent) {
750 mEditCommandsForSingleLineEditorInitialized =
751 aEvent.mEditCommandsForSingleLineEditorInitialized;
752 if (mEditCommandsForSingleLineEditorInitialized) {
753 mEditCommandsForSingleLineEditor =
754 aEvent.mEditCommandsForSingleLineEditor.Clone();
755 } else {
756 mEditCommandsForSingleLineEditor.Clear();
758 mEditCommandsForMultiLineEditorInitialized =
759 aEvent.mEditCommandsForMultiLineEditorInitialized;
760 if (mEditCommandsForMultiLineEditorInitialized) {
761 mEditCommandsForMultiLineEditor =
762 aEvent.mEditCommandsForMultiLineEditor.Clone();
763 } else {
764 mEditCommandsForMultiLineEditor.Clear();
766 mEditCommandsForRichTextEditorInitialized =
767 aEvent.mEditCommandsForRichTextEditorInitialized;
768 if (mEditCommandsForRichTextEditorInitialized) {
769 mEditCommandsForRichTextEditor =
770 aEvent.mEditCommandsForRichTextEditor.Clone();
771 } else {
772 mEditCommandsForRichTextEditor.Clear();
776 private:
777 static const char16_t* const kKeyNames[];
778 static const char16_t* const kCodeNames[];
779 typedef nsTHashMap<nsStringHashKey, KeyNameIndex> KeyNameIndexHashtable;
780 typedef nsTHashMap<nsStringHashKey, CodeNameIndex> CodeNameIndexHashtable;
781 static KeyNameIndexHashtable* sKeyNameIndexHashtable;
782 static CodeNameIndexHashtable* sCodeNameIndexHashtable;
784 // mEditCommandsFor*Editor store edit commands. This should be initialized
785 // with InitEditCommandsFor().
786 // XXX Ideally, this should be array of Command rather than CommandInt.
787 // However, ParamTraits isn't aware of enum array.
788 CopyableTArray<CommandInt> mEditCommandsForSingleLineEditor;
789 CopyableTArray<CommandInt> mEditCommandsForMultiLineEditor;
790 CopyableTArray<CommandInt> mEditCommandsForRichTextEditor;
792 nsTArray<CommandInt>& EditCommandsRef(
793 nsIWidget::NativeKeyBindingsType aType) {
794 switch (aType) {
795 case nsIWidget::NativeKeyBindingsForSingleLineEditor:
796 return mEditCommandsForSingleLineEditor;
797 case nsIWidget::NativeKeyBindingsForMultiLineEditor:
798 return mEditCommandsForMultiLineEditor;
799 case nsIWidget::NativeKeyBindingsForRichTextEditor:
800 return mEditCommandsForRichTextEditor;
801 default:
802 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
803 "Invalid native key binding type");
807 // mEditCommandsFor*EditorInitialized are set to true when
808 // InitEditCommandsFor() initializes edit commands for the type.
809 bool mEditCommandsForSingleLineEditorInitialized;
810 bool mEditCommandsForMultiLineEditorInitialized;
811 bool mEditCommandsForRichTextEditorInitialized;
813 bool& IsEditCommandsInitializedRef(nsIWidget::NativeKeyBindingsType aType) {
814 switch (aType) {
815 case nsIWidget::NativeKeyBindingsForSingleLineEditor:
816 return mEditCommandsForSingleLineEditorInitialized;
817 case nsIWidget::NativeKeyBindingsForMultiLineEditor:
818 return mEditCommandsForMultiLineEditorInitialized;
819 case nsIWidget::NativeKeyBindingsForRichTextEditor:
820 return mEditCommandsForRichTextEditorInitialized;
821 default:
822 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
823 "Invalid native key binding type");
828 /******************************************************************************
829 * mozilla::WidgetCompositionEvent
830 ******************************************************************************/
832 class WidgetCompositionEvent : public WidgetGUIEvent {
833 private:
834 friend class mozilla::dom::PBrowserParent;
835 friend class mozilla::dom::PBrowserChild;
837 WidgetCompositionEvent() : mOriginalMessage(eVoidEvent) {}
839 public:
840 virtual WidgetCompositionEvent* AsCompositionEvent() override { return this; }
842 WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage,
843 nsIWidget* aWidget)
844 : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass),
845 mNativeIMEContext(aWidget),
846 mOriginalMessage(eVoidEvent) {}
848 virtual WidgetEvent* Duplicate() const override {
849 MOZ_ASSERT(mClass == eCompositionEventClass,
850 "Duplicate() must be overridden by sub class");
851 // Not copying widget, it is a weak reference.
852 WidgetCompositionEvent* result =
853 new WidgetCompositionEvent(false, mMessage, nullptr);
854 result->AssignCompositionEventData(*this, true);
855 result->mFlags = mFlags;
856 return result;
859 // The composition string or the commit string. If the instance is a
860 // compositionstart event, this is initialized with selected text by
861 // TextComposition automatically.
862 nsString mData;
864 RefPtr<TextRangeArray> mRanges;
866 // mNativeIMEContext stores the native IME context which causes the
867 // composition event.
868 widget::NativeIMEContext mNativeIMEContext;
870 // If the instance is a clone of another event, mOriginalMessage stores
871 // the another event's mMessage.
872 EventMessage mOriginalMessage;
874 void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
875 bool aCopyTargets) {
876 AssignGUIEventData(aEvent, aCopyTargets);
878 mData = aEvent.mData;
879 mOriginalMessage = aEvent.mOriginalMessage;
880 mRanges = aEvent.mRanges;
882 // Currently, we don't need to copy the other members because they are
883 // for internal use only (not available from JS).
886 bool IsComposing() const { return mRanges && mRanges->IsComposing(); }
888 uint32_t TargetClauseOffset() const {
889 return mRanges ? mRanges->TargetClauseOffset() : 0;
892 uint32_t TargetClauseLength() const {
893 uint32_t length = UINT32_MAX;
894 if (mRanges) {
895 length = mRanges->TargetClauseLength();
897 return length == UINT32_MAX ? mData.Length() : length;
900 uint32_t RangeCount() const { return mRanges ? mRanges->Length() : 0; }
902 bool CausesDOMTextEvent() const {
903 return mMessage == eCompositionChange || mMessage == eCompositionCommit ||
904 mMessage == eCompositionCommitAsIs;
907 bool CausesDOMCompositionEndEvent() const {
908 return mMessage == eCompositionEnd || mMessage == eCompositionCommit ||
909 mMessage == eCompositionCommitAsIs;
912 bool IsFollowedByCompositionEnd() const {
913 return IsFollowedByCompositionEnd(mOriginalMessage);
916 static bool IsFollowedByCompositionEnd(EventMessage aEventMessage) {
917 return aEventMessage == eCompositionCommit ||
918 aEventMessage == eCompositionCommitAsIs;
922 /******************************************************************************
923 * mozilla::WidgetQueryContentEvent
924 ******************************************************************************/
926 class WidgetQueryContentEvent : public WidgetGUIEvent {
927 private:
928 friend class dom::PBrowserParent;
929 friend class dom::PBrowserChild;
931 WidgetQueryContentEvent()
932 : mUseNativeLineBreak(true),
933 mWithFontRanges(false),
934 mNeedsToFlushLayout(true) {
935 MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
938 public:
939 virtual WidgetQueryContentEvent* AsQueryContentEvent() override {
940 return this;
943 WidgetQueryContentEvent(bool aIsTrusted, EventMessage aMessage,
944 nsIWidget* aWidget)
945 : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eQueryContentEventClass),
946 mUseNativeLineBreak(true),
947 mWithFontRanges(false),
948 mNeedsToFlushLayout(true) {}
950 WidgetQueryContentEvent(EventMessage aMessage,
951 const WidgetQueryContentEvent& aOtherEvent)
952 : WidgetGUIEvent(aOtherEvent.IsTrusted(), aMessage,
953 const_cast<nsIWidget*>(aOtherEvent.mWidget.get()),
954 eQueryContentEventClass),
955 mUseNativeLineBreak(aOtherEvent.mUseNativeLineBreak),
956 mWithFontRanges(false),
957 mNeedsToFlushLayout(aOtherEvent.mNeedsToFlushLayout) {}
959 virtual WidgetEvent* Duplicate() const override {
960 // This event isn't an internal event of any DOM event.
961 NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
962 "WidgetQueryContentEvent needs to support Duplicate()");
963 MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
966 struct Options final {
967 bool mUseNativeLineBreak;
968 bool mRelativeToInsertionPoint;
970 explicit Options()
971 : mUseNativeLineBreak(true), mRelativeToInsertionPoint(false) {}
973 explicit Options(const WidgetQueryContentEvent& aEvent)
974 : mUseNativeLineBreak(aEvent.mUseNativeLineBreak),
975 mRelativeToInsertionPoint(aEvent.mInput.mRelativeToInsertionPoint) {}
978 void Init(const Options& aOptions) {
979 mUseNativeLineBreak = aOptions.mUseNativeLineBreak;
980 mInput.mRelativeToInsertionPoint = aOptions.mRelativeToInsertionPoint;
981 MOZ_ASSERT(mInput.IsValidEventMessage(mMessage));
984 void InitForQueryTextContent(int64_t aOffset, uint32_t aLength,
985 const Options& aOptions = Options()) {
986 NS_ASSERTION(mMessage == eQueryTextContent, "wrong initializer is called");
987 mInput.mOffset = aOffset;
988 mInput.mLength = aLength;
989 Init(aOptions);
990 MOZ_ASSERT(mInput.IsValidOffset());
993 void InitForQueryCaretRect(int64_t aOffset,
994 const Options& aOptions = Options()) {
995 NS_ASSERTION(mMessage == eQueryCaretRect, "wrong initializer is called");
996 mInput.mOffset = aOffset;
997 Init(aOptions);
998 MOZ_ASSERT(mInput.IsValidOffset());
1001 void InitForQueryTextRect(int64_t aOffset, uint32_t aLength,
1002 const Options& aOptions = Options()) {
1003 NS_ASSERTION(mMessage == eQueryTextRect, "wrong initializer is called");
1004 mInput.mOffset = aOffset;
1005 mInput.mLength = aLength;
1006 Init(aOptions);
1007 MOZ_ASSERT(mInput.IsValidOffset());
1010 void InitForQuerySelectedText(SelectionType aSelectionType,
1011 const Options& aOptions = Options()) {
1012 MOZ_ASSERT(mMessage == eQuerySelectedText);
1013 MOZ_ASSERT(aSelectionType != SelectionType::eNone);
1014 mInput.mSelectionType = aSelectionType;
1015 Init(aOptions);
1018 void InitForQueryDOMWidgetHittest(
1019 const mozilla::LayoutDeviceIntPoint& aPoint) {
1020 NS_ASSERTION(mMessage == eQueryDOMWidgetHittest,
1021 "wrong initializer is called");
1022 mRefPoint = aPoint;
1025 void InitForQueryTextRectArray(uint32_t aOffset, uint32_t aLength,
1026 const Options& aOptions = Options()) {
1027 NS_ASSERTION(mMessage == eQueryTextRectArray,
1028 "wrong initializer is called");
1029 mInput.mOffset = aOffset;
1030 mInput.mLength = aLength;
1031 Init(aOptions);
1034 bool NeedsToFlushLayout() const { return mNeedsToFlushLayout; }
1036 void RequestFontRanges() {
1037 MOZ_ASSERT(mMessage == eQueryTextContent);
1038 mWithFontRanges = true;
1041 bool Succeeded() const {
1042 if (mReply.isNothing()) {
1043 return false;
1045 switch (mMessage) {
1046 case eQuerySelectedText:
1047 return mReply->mOffsetAndData.isSome() ||
1048 mInput.mSelectionType != SelectionType::eNormal;
1049 case eQueryTextContent:
1050 case eQueryTextRect:
1051 case eQueryCaretRect:
1052 return mReply->mOffsetAndData.isSome();
1053 default:
1054 return true;
1058 bool Failed() const { return !Succeeded(); }
1060 bool FoundSelection() const {
1061 MOZ_ASSERT(mMessage == eQuerySelectedText);
1062 return Succeeded() && mReply->mOffsetAndData.isSome();
1065 bool FoundChar() const {
1066 MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
1067 return Succeeded() && mReply->mOffsetAndData.isSome();
1070 bool FoundTentativeCaretOffset() const {
1071 MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
1072 return Succeeded() && mReply->mTentativeCaretOffset.isSome();
1075 bool DidNotFindSelection() const {
1076 MOZ_ASSERT(mMessage == eQuerySelectedText);
1077 return Failed() || mReply->mOffsetAndData.isNothing();
1080 bool DidNotFindChar() const {
1081 MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
1082 return Failed() || mReply->mOffsetAndData.isNothing();
1085 bool DidNotFindTentativeCaretOffset() const {
1086 MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
1087 return Failed() || mReply->mTentativeCaretOffset.isNothing();
1090 bool mUseNativeLineBreak;
1091 bool mWithFontRanges;
1092 bool mNeedsToFlushLayout;
1093 struct Input final {
1094 uint32_t EndOffset() const {
1095 CheckedInt<uint32_t> endOffset = CheckedInt<uint32_t>(mOffset) + mLength;
1096 return NS_WARN_IF(!endOffset.isValid()) ? UINT32_MAX : endOffset.value();
1099 int64_t mOffset;
1100 uint32_t mLength;
1101 SelectionType mSelectionType;
1102 // If mOffset is true, mOffset is relative to the start offset of
1103 // composition if there is, otherwise, the start of the first selection
1104 // range.
1105 bool mRelativeToInsertionPoint;
1107 Input()
1108 : mOffset(0),
1109 mLength(0),
1110 mSelectionType(SelectionType::eNormal),
1111 mRelativeToInsertionPoint(false) {}
1113 bool IsValidOffset() const {
1114 return mRelativeToInsertionPoint || mOffset >= 0;
1116 bool IsValidEventMessage(EventMessage aEventMessage) const {
1117 if (!mRelativeToInsertionPoint) {
1118 return true;
1120 switch (aEventMessage) {
1121 case eQueryTextContent:
1122 case eQueryCaretRect:
1123 case eQueryTextRect:
1124 return true;
1125 default:
1126 return false;
1129 bool MakeOffsetAbsolute(uint32_t aInsertionPointOffset) {
1130 if (NS_WARN_IF(!mRelativeToInsertionPoint)) {
1131 return true;
1133 mRelativeToInsertionPoint = false;
1134 // If mOffset + aInsertionPointOffset becomes negative value,
1135 // we should assume the absolute offset is 0.
1136 if (mOffset < 0 && -mOffset > aInsertionPointOffset) {
1137 mOffset = 0;
1138 return true;
1140 // Otherwise, we don't allow too large offset.
1141 CheckedInt<uint32_t> absOffset(mOffset + aInsertionPointOffset);
1142 if (NS_WARN_IF(!absOffset.isValid())) {
1143 mOffset = UINT32_MAX;
1144 return false;
1146 mOffset = absOffset.value();
1147 return true;
1149 } mInput;
1151 struct Reply final {
1152 EventMessage const mEventMessage;
1153 void* mContentsRoot;
1154 Maybe<OffsetAndData<uint32_t>> mOffsetAndData;
1155 // mTentativeCaretOffset is used by only eQueryCharacterAtPoint.
1156 // This is the offset where caret would be if user clicked at the mRefPoint.
1157 Maybe<uint32_t> mTentativeCaretOffset;
1158 // mRect is used by eQueryTextRect, eQueryCaretRect, eQueryCharacterAtPoint
1159 // and eQueryEditorRect. The coordinates is system coordinates relative to
1160 // the top level widget of mFocusedWidget. E.g., if a <xul:panel> which
1161 // is owned by a window has focused editor, the offset of mRect is relative
1162 // to the owner window, not the <xul:panel>.
1163 mozilla::LayoutDeviceIntRect mRect;
1164 // The return widget has the caret. This is set at all query events.
1165 nsIWidget* mFocusedWidget;
1166 // mozilla::WritingMode value at the end (focus) of the selection
1167 mozilla::WritingMode mWritingMode;
1168 // Used by eQuerySelectionAsTransferable
1169 nsCOMPtr<nsITransferable> mTransferable;
1170 // Used by eQueryTextContent with font ranges requested
1171 CopyableAutoTArray<mozilla::FontRange, 1> mFontRanges;
1172 // Used by eQueryTextRectArray
1173 CopyableTArray<mozilla::LayoutDeviceIntRect> mRectArray;
1174 // true if selection is reversed (end < start)
1175 bool mReversed;
1176 // true if the selection exists
1177 bool mHasSelection;
1178 // true if DOM element under mouse belongs to widget
1179 bool mWidgetIsHit;
1181 Reply() = delete;
1182 explicit Reply(EventMessage aEventMessage)
1183 : mEventMessage(aEventMessage),
1184 mContentsRoot(nullptr),
1185 mFocusedWidget(nullptr),
1186 mReversed(false),
1187 mHasSelection(false),
1188 mWidgetIsHit(false) {}
1190 // Don't allow to copy/move because of `mEventMessage`.
1191 Reply(const Reply& aOther) = delete;
1192 Reply(Reply&& aOther) = delete;
1193 Reply& operator=(const Reply& aOther) = delete;
1194 Reply& operator=(Reply&& aOther) = delete;
1196 MOZ_NEVER_INLINE_DEBUG uint32_t StartOffset() const {
1197 MOZ_ASSERT(mOffsetAndData.isSome());
1198 return mOffsetAndData->StartOffset();
1200 MOZ_NEVER_INLINE_DEBUG uint32_t EndOffset() const {
1201 MOZ_ASSERT(mOffsetAndData.isSome());
1202 return mOffsetAndData->EndOffset();
1204 MOZ_NEVER_INLINE_DEBUG uint32_t DataLength() const {
1205 MOZ_ASSERT(mOffsetAndData.isSome() ||
1206 mEventMessage == eQuerySelectedText);
1207 return mOffsetAndData.isSome() ? mOffsetAndData->Length() : 0;
1209 MOZ_NEVER_INLINE_DEBUG uint32_t SelectionStartOffset() const {
1210 MOZ_ASSERT(mEventMessage == eQuerySelectedText);
1211 MOZ_ASSERT(mOffsetAndData.isSome());
1212 return StartOffset() + (mReversed ? DataLength() : 0);
1215 MOZ_NEVER_INLINE_DEBUG uint32_t SelectionEndOffset() const {
1216 MOZ_ASSERT(mEventMessage == eQuerySelectedText);
1217 MOZ_ASSERT(mOffsetAndData.isSome());
1218 return StartOffset() + (mReversed ? 0 : DataLength());
1221 const WritingMode& WritingModeRef() const {
1222 MOZ_ASSERT(mEventMessage == eQuerySelectedText ||
1223 mEventMessage == eQueryCaretRect ||
1224 mEventMessage == eQueryTextRect);
1225 MOZ_ASSERT(mOffsetAndData.isSome() ||
1226 mEventMessage == eQuerySelectedText);
1227 return mWritingMode;
1230 MOZ_NEVER_INLINE_DEBUG const nsString& DataRef() const {
1231 MOZ_ASSERT(mOffsetAndData.isSome() ||
1232 mEventMessage == eQuerySelectedText);
1233 return mOffsetAndData.isSome() ? mOffsetAndData->DataRef()
1234 : EmptyString();
1236 MOZ_NEVER_INLINE_DEBUG bool IsDataEmpty() const {
1237 MOZ_ASSERT(mOffsetAndData.isSome() ||
1238 mEventMessage == eQuerySelectedText);
1239 return mOffsetAndData.isSome() ? mOffsetAndData->IsDataEmpty() : true;
1241 MOZ_NEVER_INLINE_DEBUG bool IsOffsetInRange(uint32_t aOffset) const {
1242 MOZ_ASSERT(mOffsetAndData.isSome() ||
1243 mEventMessage == eQuerySelectedText);
1244 return mOffsetAndData.isSome() ? mOffsetAndData->IsOffsetInRange(aOffset)
1245 : false;
1247 MOZ_NEVER_INLINE_DEBUG bool IsOffsetInRangeOrEndOffset(
1248 uint32_t aOffset) const {
1249 MOZ_ASSERT(mOffsetAndData.isSome() ||
1250 mEventMessage == eQuerySelectedText);
1251 return mOffsetAndData.isSome()
1252 ? mOffsetAndData->IsOffsetInRangeOrEndOffset(aOffset)
1253 : false;
1255 MOZ_NEVER_INLINE_DEBUG void TruncateData(uint32_t aLength = 0) {
1256 MOZ_ASSERT(mOffsetAndData.isSome());
1257 mOffsetAndData->TruncateData(aLength);
1260 friend std::ostream& operator<<(std::ostream& aStream,
1261 const Reply& aReply) {
1262 aStream << "{ ";
1263 if (aReply.mEventMessage == eQuerySelectedText ||
1264 aReply.mEventMessage == eQueryTextContent ||
1265 aReply.mEventMessage == eQueryTextRect ||
1266 aReply.mEventMessage == eQueryCaretRect ||
1267 aReply.mEventMessage == eQueryCharacterAtPoint) {
1268 aStream << "mOffsetAndData=" << ToString(aReply.mOffsetAndData).c_str()
1269 << ", ";
1270 if (aReply.mEventMessage == eQueryCharacterAtPoint) {
1271 aStream << "mTentativeCaretOffset="
1272 << ToString(aReply.mTentativeCaretOffset).c_str() << ", ";
1275 aStream << "mHasSelection=" << (aReply.mHasSelection ? "true" : "false");
1276 if (aReply.mHasSelection) {
1277 if (aReply.mEventMessage == eQuerySelectedText) {
1278 aStream << ", mReversed=" << (aReply.mReversed ? "true" : "false");
1280 if (aReply.mEventMessage == eQuerySelectionAsTransferable) {
1281 aStream << ", mTransferable=0x" << aReply.mTransferable;
1284 if (aReply.mEventMessage == eQuerySelectedText ||
1285 aReply.mEventMessage == eQueryTextRect ||
1286 aReply.mEventMessage == eQueryCaretRect) {
1287 aStream << ", mWritingMode=" << ToString(aReply.mWritingMode).c_str();
1289 aStream << ", mContentsRoot=0x" << aReply.mContentsRoot
1290 << ", mFocusedWidget=0x" << aReply.mFocusedWidget;
1291 if (aReply.mEventMessage == eQueryTextContent) {
1292 aStream << ", mFontRanges={ Length()=" << aReply.mFontRanges.Length()
1293 << " }";
1294 } else if (aReply.mEventMessage == eQueryTextRect ||
1295 aReply.mEventMessage == eQueryCaretRect ||
1296 aReply.mEventMessage == eQueryCharacterAtPoint) {
1297 aStream << ", mRect=" << ToString(aReply.mRect).c_str();
1298 } else if (aReply.mEventMessage == eQueryTextRectArray) {
1299 aStream << ", mRectArray={ Length()=" << aReply.mRectArray.Length()
1300 << " }";
1301 } else if (aReply.mEventMessage == eQueryDOMWidgetHittest) {
1302 aStream << ", mWidgetIsHit="
1303 << (aReply.mWidgetIsHit ? "true" : "false");
1305 return aStream << " }";
1309 void EmplaceReply() { mReply.emplace(mMessage); }
1310 Maybe<Reply> mReply;
1312 // values of mComputedScrollAction
1313 enum { SCROLL_ACTION_NONE, SCROLL_ACTION_LINE, SCROLL_ACTION_PAGE };
1316 /******************************************************************************
1317 * mozilla::WidgetSelectionEvent
1318 ******************************************************************************/
1320 class WidgetSelectionEvent : public WidgetGUIEvent {
1321 private:
1322 friend class mozilla::dom::PBrowserParent;
1323 friend class mozilla::dom::PBrowserChild;
1325 WidgetSelectionEvent()
1326 : mOffset(0),
1327 mLength(0),
1328 mReversed(false),
1329 mExpandToClusterBoundary(true),
1330 mSucceeded(false),
1331 mUseNativeLineBreak(true),
1332 mReason(nsISelectionListener::NO_REASON) {}
1334 public:
1335 virtual WidgetSelectionEvent* AsSelectionEvent() override { return this; }
1337 WidgetSelectionEvent(bool aIsTrusted, EventMessage aMessage,
1338 nsIWidget* aWidget)
1339 : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eSelectionEventClass),
1340 mOffset(0),
1341 mLength(0),
1342 mReversed(false),
1343 mExpandToClusterBoundary(true),
1344 mSucceeded(false),
1345 mUseNativeLineBreak(true),
1346 mReason(nsISelectionListener::NO_REASON) {}
1348 virtual WidgetEvent* Duplicate() const override {
1349 // This event isn't an internal event of any DOM event.
1350 NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
1351 "WidgetSelectionEvent needs to support Duplicate()");
1352 MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()");
1353 return nullptr;
1356 // Start offset of selection
1357 uint32_t mOffset;
1358 // Length of selection
1359 uint32_t mLength;
1360 // Selection "anchor" should be in front
1361 bool mReversed;
1362 // Cluster-based or character-based
1363 bool mExpandToClusterBoundary;
1364 // true if setting selection succeeded.
1365 bool mSucceeded;
1366 // true if native line breaks are used for mOffset and mLength
1367 bool mUseNativeLineBreak;
1368 // Fennec provides eSetSelection reason codes for downstream
1369 // use in AccessibleCaret visibility logic.
1370 int16_t mReason;
1373 /******************************************************************************
1374 * mozilla::InternalEditorInputEvent
1375 ******************************************************************************/
1377 class InternalEditorInputEvent : public InternalUIEvent {
1378 private:
1379 InternalEditorInputEvent()
1380 : mData(VoidString()),
1381 mInputType(EditorInputType::eUnknown),
1382 mIsComposing(false) {}
1384 public:
1385 virtual InternalEditorInputEvent* AsEditorInputEvent() override {
1386 return this;
1389 InternalEditorInputEvent(bool aIsTrusted, EventMessage aMessage,
1390 nsIWidget* aWidget = nullptr)
1391 : InternalUIEvent(aIsTrusted, aMessage, aWidget, eEditorInputEventClass),
1392 mData(VoidString()),
1393 mInputType(EditorInputType::eUnknown) {}
1395 virtual WidgetEvent* Duplicate() const override {
1396 MOZ_ASSERT(mClass == eEditorInputEventClass,
1397 "Duplicate() must be overridden by sub class");
1398 // Not copying widget, it is a weak reference.
1399 InternalEditorInputEvent* result =
1400 new InternalEditorInputEvent(false, mMessage, nullptr);
1401 result->AssignEditorInputEventData(*this, true);
1402 result->mFlags = mFlags;
1403 return result;
1406 nsString mData;
1407 RefPtr<dom::DataTransfer> mDataTransfer;
1408 OwningNonNullStaticRangeArray mTargetRanges;
1410 EditorInputType mInputType;
1412 bool mIsComposing;
1414 void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent,
1415 bool aCopyTargets) {
1416 AssignUIEventData(aEvent, aCopyTargets);
1418 mData = aEvent.mData;
1419 mDataTransfer = aEvent.mDataTransfer;
1420 mTargetRanges = aEvent.mTargetRanges.Clone();
1421 mInputType = aEvent.mInputType;
1422 mIsComposing = aEvent.mIsComposing;
1425 void GetDOMInputTypeName(nsAString& aInputTypeName) {
1426 GetDOMInputTypeName(mInputType, aInputTypeName);
1428 static void GetDOMInputTypeName(EditorInputType aInputType,
1429 nsAString& aInputTypeName);
1430 static EditorInputType GetEditorInputType(const nsAString& aInputType);
1432 static void Shutdown();
1434 private:
1435 static const char16_t* const kInputTypeNames[];
1436 typedef nsTHashMap<nsStringHashKey, EditorInputType> InputTypeHashtable;
1437 static InputTypeHashtable* sInputTypeHashtable;
1440 } // namespace mozilla
1442 #endif // mozilla_TextEvents_h__