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/. */
5 
6 #ifndef mozilla_TextEvents_h__
7 #define mozilla_TextEvents_h__
8 
9 #include <stdint.h>
10 
11 #include "mozilla/Assertions.h"
12 #include "mozilla/BasicEvents.h"
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/dom/DataTransfer.h"
15 #include "mozilla/dom/StaticRange.h"
16 #include "mozilla/EventForwards.h"  // for KeyNameIndex, temporarily
17 #include "mozilla/FontRange.h"
18 #include "mozilla/Maybe.h"
19 #include "mozilla/OwningNonNull.h"
20 #include "mozilla/TextRange.h"
21 #include "mozilla/WritingModes.h"
22 #include "mozilla/dom/KeyboardEventBinding.h"
23 #include "nsCOMPtr.h"
24 #include "nsISelectionListener.h"
25 #include "nsITransferable.h"
26 #include "nsRect.h"
27 #include "nsString.h"
28 #include "nsTArray.h"
29 
30 class nsStringHashKey;
31 template <class, class>
32 class nsDataHashtable;
33 
34 /******************************************************************************
35  * virtual keycode values
36  ******************************************************************************/
37 
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
43 };
44 
45 namespace mozilla {
46 
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
52 };
53 
54 const nsCString GetDOMKeyCodeName(uint32_t aKeyCode);
55 
56 namespace dom {
57 class PBrowserParent;
58 class PBrowserChild;
59 }  // namespace dom
60 namespace plugins {
61 class PPluginInstanceChild;
62 }  // namespace plugins
63 
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
71 };
72 
73 /******************************************************************************
74  * mozilla::AlternativeCharCode
75  *
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  ******************************************************************************/
79 
80 struct AlternativeCharCode {
AlternativeCharCodeAlternativeCharCode81   AlternativeCharCode() : mUnshiftedCharCode(0), mShiftedCharCode(0) {}
AlternativeCharCodeAlternativeCharCode82   AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode)
83       : mUnshiftedCharCode(aUnshiftedCharCode),
84         mShiftedCharCode(aShiftedCharCode) {}
85   uint32_t mUnshiftedCharCode;
86   uint32_t mShiftedCharCode;
87 };
88 
89 /******************************************************************************
90  * mozilla::ShortcutKeyCandidate
91  *
92  * This stores a candidate of shortcut key combination.
93  ******************************************************************************/
94 
95 struct ShortcutKeyCandidate {
ShortcutKeyCandidateShortcutKeyCandidate96   ShortcutKeyCandidate() : mCharCode(0), mIgnoreShift(0) {}
ShortcutKeyCandidateShortcutKeyCandidate97   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;
104 };
105 
106 /******************************************************************************
107  * mozilla::IgnoreModifierState
108  *
109  * This stores flags for modifiers that should be ignored when matching
110  * XBL handlers.
111  ******************************************************************************/
112 
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;
118 
IgnoreModifierStateIgnoreModifierState119   IgnoreModifierState() : mShift(false), mOS(false) {}
120 };
121 
122 /******************************************************************************
123  * mozilla::WidgetKeyboardEvent
124  ******************************************************************************/
125 
126 class WidgetKeyboardEvent : public WidgetInputEvent {
127  private:
128   friend class dom::PBrowserParent;
129   friend class dom::PBrowserChild;
130   friend struct IPC::ParamTraits<WidgetKeyboardEvent>;
131 
132  protected:
133   WidgetKeyboardEvent()
134       : mNativeKeyEvent(nullptr),
135         mKeyCode(0),
136         mCharCode(0),
137         mPseudoCharCode(0),
138         mLocation(eKeyLocationStandard),
139         mUniqueId(0)
140 #ifdef XP_MACOSX
141         ,
142         mNativeModifierFlags(0),
143         mNativeKeyCode(0)
144 #endif  // #ifdef XP_MACOSX
145         ,
146         mKeyNameIndex(KEY_NAME_INDEX_Unidentified),
147         mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN),
148         mIsRepeat(false),
149         mIsComposing(false),
150         mIsSynthesizedByTIP(false),
151         mMaybeSkippableInRemoteProcess(true),
152         mUseLegacyKeyCodeAndCharCodeValues(false),
153         mEditCommandsForSingleLineEditorInitialized(false),
154         mEditCommandsForMultiLineEditorInitialized(false),
155         mEditCommandsForRichTextEditorInitialized(false) {
156   }
157 
158  public:
159   virtual WidgetKeyboardEvent* AsKeyboardEvent() override { return this; }
160 
161   WidgetKeyboardEvent(bool aIsTrusted, EventMessage aMessage,
162                       nsIWidget* aWidget,
163                       EventClassID aEventClassID = eKeyboardEventClass)
164       : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID),
165         mNativeKeyEvent(nullptr),
166         mKeyCode(0),
167         mCharCode(0),
168         mPseudoCharCode(0),
169         mLocation(eKeyLocationStandard),
170         mUniqueId(0)
171 #ifdef XP_MACOSX
172         ,
173         mNativeModifierFlags(0),
174         mNativeKeyCode(0)
175 #endif  // #ifdef XP_MACOSX
176         ,
177         mKeyNameIndex(KEY_NAME_INDEX_Unidentified),
178         mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN),
179         mIsRepeat(false),
180         mIsComposing(false),
181         mIsSynthesizedByTIP(false),
182         mMaybeSkippableInRemoteProcess(true),
183         mUseLegacyKeyCodeAndCharCodeValues(false),
184         mEditCommandsForSingleLineEditorInitialized(false),
185         mEditCommandsForMultiLineEditorInitialized(false),
186         mEditCommandsForRichTextEditorInitialized(false) {
187     // If this is a keyboard event on a plugin, it shouldn't fired on content.
188     if (IsKeyEventOnPlugin()) {
189       mFlags.mOnlySystemGroupDispatchInContent = true;
190       StopCrossProcessForwarding();
191     }
192   }
193 
194   static bool IsKeyDownOrKeyDownOnPlugin(EventMessage aMessage) {
195     return aMessage == eKeyDown || aMessage == eKeyDownOnPlugin;
196   }
197   bool IsKeyDownOrKeyDownOnPlugin() const {
198     return IsKeyDownOrKeyDownOnPlugin(mMessage);
199   }
200   static bool IsKeyUpOrKeyUpOnPlugin(EventMessage aMessage) {
201     return aMessage == eKeyUp || aMessage == eKeyUpOnPlugin;
202   }
203   bool IsKeyUpOrKeyUpOnPlugin() const {
204     return IsKeyUpOrKeyUpOnPlugin(mMessage);
205   }
206   static bool IsKeyEventOnPlugin(EventMessage aMessage) {
207     return aMessage == eKeyDownOnPlugin || aMessage == eKeyUpOnPlugin;
208   }
209   bool IsKeyEventOnPlugin() const { return IsKeyEventOnPlugin(mMessage); }
210 
211   // IsInputtingText() and IsInputtingLineBreak() are used to check if
212   // it should cause eKeyPress events even on web content.
213   // UI Events defines that "keypress" event should be fired "if and only if
214   // that key normally produces a character value".
215   // <https://www.w3.org/TR/uievents/#event-type-keypress>
216   // Additionally, for backward compatiblity with all existing browsers,
217   // there is a spec issue for Enter key press.
218   // <https://github.com/w3c/uievents/issues/183>
219   bool IsInputtingText() const {
220     // NOTE: On some keyboard layout, some characters are inputted with Control
221     //       key or Alt key, but at that time, widget clears the modifier flag
222     //       from eKeyPress event because our TextEditor won't handle eKeyPress
223     //       events as inputting text (bug 1346832).
224     // NOTE: There are some complicated issues of our traditional behavior.
225     //       -- On Windows, KeyboardLayout::WillDispatchKeyboardEvent() clears
226     //       MODIFIER_ALT and MODIFIER_CONTROL of eKeyPress event if it
227     //       should be treated as inputting a character because AltGr is
228     //       represented with both Alt key and Ctrl key are pressed, and
229     //       some keyboard layouts may produces a character with Ctrl key.
230     //       -- On Linux, KeymapWrapper doesn't have this hack since perhaps,
231     //       we don't have any bug reports that user cannot input proper
232     //       character with Alt and/or Ctrl key.
233     //       -- On macOS, IMEInputHandler::WillDispatchKeyboardEvent() clears
234     //       MODIFIER_ALT and MDOFIEIR_CONTROL of eKeyPress event only when
235     //       TextInputHandler::InsertText() has been called for the event.
236     //       I.e., they are cleared only when an editor has focus (even if IME
237     //       is disabled in password field or by |ime-mode: disabled;|) because
238     //       TextInputHandler::InsertText() is called while
239     //       TextInputHandler::HandleKeyDownEvent() calls interpretKeyEvents:
240     //       to notify text input processor of Cocoa (including IME).  In other
241     //       words, when we need to disable IME completey when no editor has
242     //       focus, we cannot call interpretKeyEvents:.  So,
243     //       TextInputHandler::InsertText() won't be called when no editor has
244     //       focus so that neither MODIFIER_ALT nor MODIFIER_CONTROL is
245     //       cleared.  So, fortunately, altKey and ctrlKey values of "keypress"
246     //       events are same as the other browsers only when no editor has
247     //       focus.
248     // NOTE: As mentioned above, for compatibility with the other browsers on
249     //       macOS, we should keep MODIFIER_ALT and MODIFIER_CONTROL flags of
250     //       eKeyPress events when no editor has focus.  However, Alt key,
251     //       labeled "option" on keyboard for Mac, is AltGraph key on the other
252     //       platforms.  So, even if MODIFIER_ALT is set, we need to dispatch
253     //       eKeyPress event even on web content unless mCharCode is 0.
254     //       Therefore, we need to ignore MODIFIER_ALT flag here only on macOS.
255     return mMessage == eKeyPress && mCharCode &&
256            !(mModifiers & (
257 #ifndef XP_MACOSX
258                               // So, ignore MODIFIER_ALT only on macOS since
259                               // option key is used as AltGraph key on macOS.
260                               MODIFIER_ALT |
261 #endif  // #ifndef XP_MAXOSX
262                               MODIFIER_CONTROL | MODIFIER_META | MODIFIER_OS));
263   }
264 
265   bool IsInputtingLineBreak() const {
266     return mMessage == eKeyPress && mKeyNameIndex == KEY_NAME_INDEX_Enter &&
267            !(mModifiers &
268              (MODIFIER_ALT | MODIFIER_CONTROL | MODIFIER_META | MODIFIER_OS));
269   }
270 
271   /**
272    * ShouldKeyPressEventBeFiredOnContent() should be called only when the
273    * instance is eKeyPress event.  This returns true when the eKeyPress
274    * event should be fired even on content in the default event group.
275    */
276   bool ShouldKeyPressEventBeFiredOnContent() const {
277     MOZ_DIAGNOSTIC_ASSERT(mMessage == eKeyPress);
278     if (IsInputtingText() || IsInputtingLineBreak()) {
279       return true;
280     }
281     // Ctrl + Enter won't cause actual input in our editor.
282     // However, the other browsers fire keypress event in any platforms.
283     // So, for compatibility with them, we should fire keypress event for
284     // Ctrl + Enter too.
285     return mMessage == eKeyPress && mKeyNameIndex == KEY_NAME_INDEX_Enter &&
286            !(mModifiers &
287              (MODIFIER_ALT | MODIFIER_META | MODIFIER_OS | MODIFIER_SHIFT));
288   }
289 
290   virtual WidgetEvent* Duplicate() const override {
291     MOZ_ASSERT(mClass == eKeyboardEventClass,
292                "Duplicate() must be overridden by sub class");
293     // Not copying widget, it is a weak reference.
294     WidgetKeyboardEvent* result =
295         new WidgetKeyboardEvent(false, mMessage, nullptr);
296     result->AssignKeyEventData(*this, true);
297     result->mEditCommandsForSingleLineEditor =
298         mEditCommandsForSingleLineEditor.Clone();
299     result->mEditCommandsForMultiLineEditor =
300         mEditCommandsForMultiLineEditor.Clone();
301     result->mEditCommandsForRichTextEditor =
302         mEditCommandsForRichTextEditor.Clone();
303     result->mFlags = mFlags;
304     return result;
305   }
306 
307   bool CanUserGestureActivateTarget() const {
308     // Printable keys, 'carriage return' and 'space' are supported user gestures
309     // for activating the document. However, if supported key is being pressed
310     // combining with other operation keys, such like alt, control ..etc., we
311     // won't activate the target for them because at that time user might
312     // interact with browser or window manager which doesn't necessarily
313     // demonstrate user's intent to play media.
314     const bool isCombiningWithOperationKeys = (IsControl() && !IsAltGraph()) ||
315                                               (IsAlt() && !IsAltGraph()) ||
316                                               IsMeta() || IsOS();
317     const bool isEnterOrSpaceKey =
318         mKeyNameIndex == KEY_NAME_INDEX_Enter || mKeyCode == NS_VK_SPACE;
319     return (PseudoCharCode() || isEnterOrSpaceKey) &&
320            (!isCombiningWithOperationKeys ||
321             // ctrl-c/ctrl-x/ctrl-v is quite common shortcut for clipboard
322             // operation.
323             // XXXedgar, we have to find a better way to handle browser keyboard
324             // shortcut for user activation, instead of just ignoring all
325             // combinations, see bug 1641171.
326             ((mKeyCode == dom::KeyboardEvent_Binding::DOM_VK_C ||
327               mKeyCode == dom::KeyboardEvent_Binding::DOM_VK_V ||
328               mKeyCode == dom::KeyboardEvent_Binding::DOM_VK_X) &&
329              IsAccel()));
330   }
331 
332   /**
333    * CanTreatAsUserInput() returns true if the key is pressed for perhaps
334    * doing something on the web app or our UI.  This means that when this
335    * returns false, e.g., when user presses a modifier key, user is probably
336    * displeased by opening popup, entering fullscreen mode, etc.  Therefore,
337    * only when this returns true, such reactions should be allowed.
338    */
339   bool CanTreatAsUserInput() const {
340     if (!IsTrusted()) {
341       return false;
342     }
343     switch (mKeyNameIndex) {
344       case KEY_NAME_INDEX_Escape:
345       // modifier keys:
346       case KEY_NAME_INDEX_Alt:
347       case KEY_NAME_INDEX_AltGraph:
348       case KEY_NAME_INDEX_CapsLock:
349       case KEY_NAME_INDEX_Control:
350       case KEY_NAME_INDEX_Fn:
351       case KEY_NAME_INDEX_FnLock:
352       case KEY_NAME_INDEX_Meta:
353       case KEY_NAME_INDEX_NumLock:
354       case KEY_NAME_INDEX_ScrollLock:
355       case KEY_NAME_INDEX_Shift:
356       case KEY_NAME_INDEX_Symbol:
357       case KEY_NAME_INDEX_SymbolLock:
358       // legacy modifier keys:
359       case KEY_NAME_INDEX_Hyper:
360       case KEY_NAME_INDEX_Super:
361       // obsolete modifier key:
362       case KEY_NAME_INDEX_OS:
363         return false;
364       default:
365         return true;
366     }
367   }
368 
369   /**
370    * ShouldInteractionTimeRecorded() returns true if the handling time of
371    * the event should be recorded with the telemetry.
372    */
373   bool ShouldInteractionTimeRecorded() const {
374     // Let's record only when we can treat the instance is a user input.
375     return CanTreatAsUserInput();
376   }
377 
378   // OS translated Unicode chars which are used for accesskey and accelkey
379   // handling. The handlers will try from first character to last character.
380   CopyableTArray<AlternativeCharCode> mAlternativeCharCodes;
381   // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING.
382   nsString mKeyValue;
383   // DOM KeyboardEvent.code only when mCodeNameIndex is
384   // CODE_NAME_INDEX_USE_STRING.
385   nsString mCodeValue;
386 
387 #ifdef XP_MACOSX
388   // Values given by a native NSEvent, for use with Cocoa NPAPI plugins.
389   nsString mNativeCharacters;
390   nsString mNativeCharactersIgnoringModifiers;
391   // If this is non-empty, create a text event for plugins instead of a
392   // keyboard event.
393   nsString mPluginTextEventString;
394 #endif  // #ifdef XP_MACOSX
395 
396   // OS-specific native event can optionally be preserved
397   void* mNativeKeyEvent;
398   // A DOM keyCode value or 0.  If a keypress event whose mCharCode is 0, this
399   // should be 0.
400   uint32_t mKeyCode;
401   // If the instance is a keypress event of a printable key, this is a UTF-16
402   // value of the key.  Otherwise, 0.  This value must not be a control
403   // character when some modifiers are active.  Then, this value should be an
404   // unmodified value except Shift and AltGr.
405   uint32_t mCharCode;
406   // mPseudoCharCode is valid only when mMessage is an eKeyDown event.
407   // This stores mCharCode value of keypress event which is fired with same
408   // key value and same modifier state.
409   uint32_t mPseudoCharCode;
410   // One of eKeyLocation*
411   uint32_t mLocation;
412   // Unique id associated with a keydown / keypress event. It's ok if this wraps
413   // over long periods.
414   uint32_t mUniqueId;
415 
416 #ifdef XP_MACOSX
417   // Values given by a native NSEvent, for use with Cocoa NPAPI plugins.
418   uint32_t mNativeModifierFlags;
419   uint16_t mNativeKeyCode;
420 #endif  // #ifdef XP_MACOSX
421 
422   // DOM KeyboardEvent.key
423   KeyNameIndex mKeyNameIndex;
424   // DOM KeyboardEvent.code
425   CodeNameIndex mCodeNameIndex;
426 
427   // Indicates whether the event is generated by auto repeat or not.
428   // if this is keyup event, always false.
429   bool mIsRepeat;
430   // Indicates whether the event is generated during IME (or deadkey)
431   // composition.  This is initialized by EventStateManager.  So, key event
432   // dispatchers don't need to initialize this.
433   bool mIsComposing;
434   // Indicates whether the event is synthesized from Text Input Processor
435   // or an actual event from nsAppShell.
436   bool mIsSynthesizedByTIP;
437   // Indicates whether the event is skippable in remote process.
438   // Don't refer this member directly when you need to check this.
439   // Use CanSkipInRemoteProcess() instead.
440   bool mMaybeSkippableInRemoteProcess;
441   // Indicates whether the event should return legacy keyCode value and
442   // charCode value to web apps (one of them is always 0) or not, when it's
443   // an eKeyPress event.
444   bool mUseLegacyKeyCodeAndCharCodeValues;
445 
446   bool CanSkipInRemoteProcess() const {
447     // If this is a repeat event (i.e., generated by auto-repeat feature of
448     // the platform), remove process may skip to handle it because of
449     // performances reasons..  However, if it's caused by odd keyboard utils,
450     // we should not ignore any key events even marked as repeated since
451     // generated key sequence may be important to input proper text.  E.g.,
452     // "SinhalaTamil IME" on Windows emulates dead key like input with
453     // generating WM_KEYDOWN for VK_PACKET (inputting any Unicode characters
454     // without keyboard layout information) and VK_BACK (Backspace) to remove
455     // previous character(s) and those messages may be marked as "repeat" by
456     // their bug.
457     return mIsRepeat && mMaybeSkippableInRemoteProcess;
458   }
459 
460   /**
461    * Retrieves all edit commands from mWidget.  This shouldn't be called when
462    * the instance is an untrusted event, doesn't have widget or in non-chrome
463    * process.
464    */
465   void InitAllEditCommands();
466 
467   /**
468    * Retrieves edit commands from mWidget only for aType.  This shouldn't be
469    * called when the instance is an untrusted event or doesn't have widget.
470    *
471    * @return            false if some resource is not available to get
472    *                    commands unexpectedly.  Otherwise, true even if
473    *                    retrieved command is nothing.
474    */
475   bool InitEditCommandsFor(nsIWidget::NativeKeyBindingsType aType);
476 
477   /**
478    * PreventNativeKeyBindings() makes the instance to not cause any edit
479    * actions even if it matches with a native key binding.
480    */
481   void PreventNativeKeyBindings() {
482     mEditCommandsForSingleLineEditor.Clear();
483     mEditCommandsForMultiLineEditor.Clear();
484     mEditCommandsForRichTextEditor.Clear();
485     mEditCommandsForSingleLineEditorInitialized = true;
486     mEditCommandsForMultiLineEditorInitialized = true;
487     mEditCommandsForRichTextEditorInitialized = true;
488   }
489 
490   /**
491    * EditCommandsConstRef() returns reference to edit commands for aType.
492    */
493   const nsTArray<CommandInt>& EditCommandsConstRef(
494       nsIWidget::NativeKeyBindingsType aType) const {
495     return const_cast<WidgetKeyboardEvent*>(this)->EditCommandsRef(aType);
496   }
497 
498   /**
499    * IsEditCommandsInitialized() returns true if edit commands for aType
500    * was already initialized.  Otherwise, false.
501    */
502   bool IsEditCommandsInitialized(nsIWidget::NativeKeyBindingsType aType) const {
503     return const_cast<WidgetKeyboardEvent*>(this)->IsEditCommandsInitializedRef(
504         aType);
505   }
506 
507 #ifdef DEBUG
508   /**
509    * AreAllEditCommandsInitialized() returns true if edit commands for all
510    * types were already initialized.  Otherwise, false.
511    */
512   bool AreAllEditCommandsInitialized() const {
513     return mEditCommandsForSingleLineEditorInitialized &&
514            mEditCommandsForMultiLineEditorInitialized &&
515            mEditCommandsForRichTextEditorInitialized;
516   }
517 #endif  // #ifdef DEBUG
518 
519   /**
520    * Execute edit commands for aType.
521    *
522    * @return        true if the caller should do nothing anymore.
523    *                false, otherwise.
524    */
525   typedef void (*DoCommandCallback)(Command, void*);
526   bool ExecuteEditCommands(nsIWidget::NativeKeyBindingsType aType,
527                            DoCommandCallback aCallback, void* aCallbackData);
528 
529   // If the key should cause keypress events, this returns true.
530   // Otherwise, false.
531   bool ShouldCauseKeypressEvents() const;
532 
533   // mCharCode value of non-eKeyPress events is always 0.  However, if
534   // non-eKeyPress event has one or more alternative char code values,
535   // its first item should be the mCharCode value of following eKeyPress event.
536   // PseudoCharCode() returns mCharCode value for eKeyPress event,
537   // the first alternative char code value of non-eKeyPress event or 0.
538   uint32_t PseudoCharCode() const {
539     return mMessage == eKeyPress ? mCharCode : mPseudoCharCode;
540   }
541   void SetCharCode(uint32_t aCharCode) {
542     if (mMessage == eKeyPress) {
543       mCharCode = aCharCode;
544     } else {
545       mPseudoCharCode = aCharCode;
546     }
547   }
548 
549   void GetDOMKeyName(nsAString& aKeyName) {
550     if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
551       aKeyName = mKeyValue;
552       return;
553     }
554     GetDOMKeyName(mKeyNameIndex, aKeyName);
555   }
556   void GetDOMCodeName(nsAString& aCodeName) {
557     if (mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
558       aCodeName = mCodeValue;
559       return;
560     }
561     GetDOMCodeName(mCodeNameIndex, aCodeName);
562   }
563 
564   /**
565    * GetFallbackKeyCodeOfPunctuationKey() returns a DOM keyCode value for
566    * aCodeNameIndex.  This is keyCode value of the key when active keyboard
567    * layout is ANSI (US), JIS or ABNT keyboard layout (the latter 2 layouts
568    * are used only when ANSI doesn't have the key).  The result is useful
569    * if the key doesn't produce ASCII character with active keyboard layout
570    * nor with alternative ASCII capable keyboard layout.
571    */
572   static uint32_t GetFallbackKeyCodeOfPunctuationKey(
573       CodeNameIndex aCodeNameIndex);
574 
575   bool IsModifierKeyEvent() const {
576     return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE;
577   }
578 
579   /**
580    * Get the candidates for shortcut key.
581    *
582    * @param aCandidates [out] the candidate shortcut key combination list.
583    *                          the first item is most preferred.
584    */
585   void GetShortcutKeyCandidates(ShortcutKeyCandidateArray& aCandidates) const;
586 
587   /**
588    * Get the candidates for access key.
589    *
590    * @param aCandidates [out] the candidate access key list.
591    *                          the first item is most preferred.
592    */
593   void GetAccessKeyCandidates(nsTArray<uint32_t>& aCandidates) const;
594 
595   /**
596    * Check whether the modifiers match with chrome access key or
597    * content access key.
598    */
599   bool ModifiersMatchWithAccessKey(AccessKeyType aType) const;
600 
601   /**
602    * Return active modifiers which may match with access key.
603    * For example, even if Alt is access key modifier, then, when Control,
604    * CapseLock and NumLock are active, this returns only MODIFIER_CONTROL.
605    */
606   Modifiers ModifiersForAccessKeyMatching() const;
607 
608   /**
609    * Return access key modifiers.
610    */
611   static Modifiers AccessKeyModifiers(AccessKeyType aType);
612 
613   static void Shutdown();
614 
615   /**
616    * ComputeLocationFromCodeValue() returns one of .mLocation value
617    * (eKeyLocation*) which is the most preferred value for the specified code
618    * value.
619    */
620   static uint32_t ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex);
621 
622   /**
623    * ComputeKeyCodeFromKeyNameIndex() return a .mKeyCode value which can be
624    * mapped from the specified key value.  Note that this returns 0 if the
625    * key name index is KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING.
626    * This means that this method is useful only for non-printable keys.
627    */
628   static uint32_t ComputeKeyCodeFromKeyNameIndex(KeyNameIndex aKeyNameIndex);
629 
630   /**
631    * ComputeCodeNameIndexFromKeyNameIndex() returns a code name index which
632    * is typically mapped to given key name index on the platform.
633    * Note that this returns CODE_NAME_INDEX_UNKNOWN if the key name index is
634    * KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING.
635    * This means that this method is useful only for non-printable keys.
636    *
637    * @param aKeyNameIndex      A non-printable key name index.
638    * @param aLocation          Should be one of location value.  This is
639    *                           important when aKeyNameIndex may exist in
640    *                           both Numpad or Standard, or in both Left or
641    *                           Right.  If this is nothing, this method
642    *                           returns Left or Standard position's code
643    *                           value.
644    */
645   static CodeNameIndex ComputeCodeNameIndexFromKeyNameIndex(
646       KeyNameIndex aKeyNameIndex, const Maybe<uint32_t>& aLocation);
647 
648   /**
649    * GetModifierForKeyName() returns a value of Modifier which is activated
650    * by the aKeyNameIndex.
651    */
652   static Modifier GetModifierForKeyName(KeyNameIndex aKeyNameIndex);
653 
654   /**
655    * IsLeftOrRightModiferKeyNameIndex() returns true if aKeyNameIndex is a
656    * modifier key which may be in Left and Right location.
657    */
658   static bool IsLeftOrRightModiferKeyNameIndex(KeyNameIndex aKeyNameIndex) {
659     switch (aKeyNameIndex) {
660       case KEY_NAME_INDEX_Alt:
661       case KEY_NAME_INDEX_Control:
662       case KEY_NAME_INDEX_Meta:
663       case KEY_NAME_INDEX_OS:
664       case KEY_NAME_INDEX_Shift:
665         return true;
666       default:
667         return false;
668     }
669   }
670 
671   /**
672    * IsLockableModifier() returns true if aKeyNameIndex is a lockable modifier
673    * key such as CapsLock and NumLock.
674    */
675   static bool IsLockableModifier(KeyNameIndex aKeyNameIndex);
676 
677   static void GetDOMKeyName(KeyNameIndex aKeyNameIndex, nsAString& aKeyName);
678   static void GetDOMCodeName(CodeNameIndex aCodeNameIndex,
679                              nsAString& aCodeName);
680 
681   static KeyNameIndex GetKeyNameIndex(const nsAString& aKeyValue);
682   static CodeNameIndex GetCodeNameIndex(const nsAString& aCodeValue);
683 
684   static const char* GetCommandStr(Command aCommand);
685 
686   void AssignKeyEventData(const WidgetKeyboardEvent& aEvent,
687                           bool aCopyTargets) {
688     AssignInputEventData(aEvent, aCopyTargets);
689 
690     mKeyCode = aEvent.mKeyCode;
691     mCharCode = aEvent.mCharCode;
692     mPseudoCharCode = aEvent.mPseudoCharCode;
693     mLocation = aEvent.mLocation;
694     mAlternativeCharCodes = aEvent.mAlternativeCharCodes.Clone();
695     mIsRepeat = aEvent.mIsRepeat;
696     mIsComposing = aEvent.mIsComposing;
697     mKeyNameIndex = aEvent.mKeyNameIndex;
698     mCodeNameIndex = aEvent.mCodeNameIndex;
699     mKeyValue = aEvent.mKeyValue;
700     mCodeValue = aEvent.mCodeValue;
701     // Don't copy mNativeKeyEvent because it may be referred after its instance
702     // is destroyed.
703     mNativeKeyEvent = nullptr;
704     mUniqueId = aEvent.mUniqueId;
705 #ifdef XP_MACOSX
706     mNativeKeyCode = aEvent.mNativeKeyCode;
707     mNativeModifierFlags = aEvent.mNativeModifierFlags;
708     mNativeCharacters.Assign(aEvent.mNativeCharacters);
709     mNativeCharactersIgnoringModifiers.Assign(
710         aEvent.mNativeCharactersIgnoringModifiers);
711     mPluginTextEventString.Assign(aEvent.mPluginTextEventString);
712 #endif
713     mIsSynthesizedByTIP = aEvent.mIsSynthesizedByTIP;
714     mMaybeSkippableInRemoteProcess = aEvent.mMaybeSkippableInRemoteProcess;
715     mUseLegacyKeyCodeAndCharCodeValues =
716         aEvent.mUseLegacyKeyCodeAndCharCodeValues;
717 
718     // Don't copy mEditCommandsFor*Editor because it may require a lot of
719     // memory space.  For example, if the event is dispatched but grabbed by
720     // a JS variable, they are not necessary anymore.
721 
722     mEditCommandsForSingleLineEditorInitialized =
723         aEvent.mEditCommandsForSingleLineEditorInitialized;
724     mEditCommandsForMultiLineEditorInitialized =
725         aEvent.mEditCommandsForMultiLineEditorInitialized;
726     mEditCommandsForRichTextEditorInitialized =
727         aEvent.mEditCommandsForRichTextEditorInitialized;
728   }
729 
730   void AssignCommands(const WidgetKeyboardEvent& aEvent) {
731     mEditCommandsForSingleLineEditorInitialized =
732         aEvent.mEditCommandsForSingleLineEditorInitialized;
733     if (mEditCommandsForSingleLineEditorInitialized) {
734       mEditCommandsForSingleLineEditor =
735           aEvent.mEditCommandsForSingleLineEditor.Clone();
736     } else {
737       mEditCommandsForSingleLineEditor.Clear();
738     }
739     mEditCommandsForMultiLineEditorInitialized =
740         aEvent.mEditCommandsForMultiLineEditorInitialized;
741     if (mEditCommandsForMultiLineEditorInitialized) {
742       mEditCommandsForMultiLineEditor =
743           aEvent.mEditCommandsForMultiLineEditor.Clone();
744     } else {
745       mEditCommandsForMultiLineEditor.Clear();
746     }
747     mEditCommandsForRichTextEditorInitialized =
748         aEvent.mEditCommandsForRichTextEditorInitialized;
749     if (mEditCommandsForRichTextEditorInitialized) {
750       mEditCommandsForRichTextEditor =
751           aEvent.mEditCommandsForRichTextEditor.Clone();
752     } else {
753       mEditCommandsForRichTextEditor.Clear();
754     }
755   }
756 
757  private:
758   static const char16_t* const kKeyNames[];
759   static const char16_t* const kCodeNames[];
760   typedef nsDataHashtable<nsStringHashKey, KeyNameIndex> KeyNameIndexHashtable;
761   typedef nsDataHashtable<nsStringHashKey, CodeNameIndex>
762       CodeNameIndexHashtable;
763   static KeyNameIndexHashtable* sKeyNameIndexHashtable;
764   static CodeNameIndexHashtable* sCodeNameIndexHashtable;
765 
766   // mEditCommandsFor*Editor store edit commands.  This should be initialized
767   // with InitEditCommandsFor().
768   // XXX Ideally, this should be array of Command rather than CommandInt.
769   //     However, ParamTraits isn't aware of enum array.
770   CopyableTArray<CommandInt> mEditCommandsForSingleLineEditor;
771   CopyableTArray<CommandInt> mEditCommandsForMultiLineEditor;
772   CopyableTArray<CommandInt> mEditCommandsForRichTextEditor;
773 
774   nsTArray<CommandInt>& EditCommandsRef(
775       nsIWidget::NativeKeyBindingsType aType) {
776     switch (aType) {
777       case nsIWidget::NativeKeyBindingsForSingleLineEditor:
778         return mEditCommandsForSingleLineEditor;
779       case nsIWidget::NativeKeyBindingsForMultiLineEditor:
780         return mEditCommandsForMultiLineEditor;
781       case nsIWidget::NativeKeyBindingsForRichTextEditor:
782         return mEditCommandsForRichTextEditor;
783       default:
784         MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
785             "Invalid native key binding type");
786     }
787   }
788 
789   // mEditCommandsFor*EditorInitialized are set to true when
790   // InitEditCommandsFor() initializes edit commands for the type.
791   bool mEditCommandsForSingleLineEditorInitialized;
792   bool mEditCommandsForMultiLineEditorInitialized;
793   bool mEditCommandsForRichTextEditorInitialized;
794 
795   bool& IsEditCommandsInitializedRef(nsIWidget::NativeKeyBindingsType aType) {
796     switch (aType) {
797       case nsIWidget::NativeKeyBindingsForSingleLineEditor:
798         return mEditCommandsForSingleLineEditorInitialized;
799       case nsIWidget::NativeKeyBindingsForMultiLineEditor:
800         return mEditCommandsForMultiLineEditorInitialized;
801       case nsIWidget::NativeKeyBindingsForRichTextEditor:
802         return mEditCommandsForRichTextEditorInitialized;
803       default:
804         MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
805             "Invalid native key binding type");
806     }
807   }
808 };
809 
810 /******************************************************************************
811  * mozilla::WidgetCompositionEvent
812  ******************************************************************************/
813 
814 class WidgetCompositionEvent : public WidgetGUIEvent {
815  private:
816   friend class mozilla::dom::PBrowserParent;
817   friend class mozilla::dom::PBrowserChild;
818 
819   WidgetCompositionEvent() : mOriginalMessage(eVoidEvent) {}
820 
821  public:
822   virtual WidgetCompositionEvent* AsCompositionEvent() override { return this; }
823 
824   WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage,
825                          nsIWidget* aWidget)
826       : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass),
827         mNativeIMEContext(aWidget),
828         mOriginalMessage(eVoidEvent) {}
829 
830   virtual WidgetEvent* Duplicate() const override {
831     MOZ_ASSERT(mClass == eCompositionEventClass,
832                "Duplicate() must be overridden by sub class");
833     // Not copying widget, it is a weak reference.
834     WidgetCompositionEvent* result =
835         new WidgetCompositionEvent(false, mMessage, nullptr);
836     result->AssignCompositionEventData(*this, true);
837     result->mFlags = mFlags;
838     return result;
839   }
840 
841   // The composition string or the commit string.  If the instance is a
842   // compositionstart event, this is initialized with selected text by
843   // TextComposition automatically.
844   nsString mData;
845 
846   RefPtr<TextRangeArray> mRanges;
847 
848   // mNativeIMEContext stores the native IME context which causes the
849   // composition event.
850   widget::NativeIMEContext mNativeIMEContext;
851 
852   // If the instance is a clone of another event, mOriginalMessage stores
853   // the another event's mMessage.
854   EventMessage mOriginalMessage;
855 
856   void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
857                                   bool aCopyTargets) {
858     AssignGUIEventData(aEvent, aCopyTargets);
859 
860     mData = aEvent.mData;
861     mOriginalMessage = aEvent.mOriginalMessage;
862     mRanges = aEvent.mRanges;
863 
864     // Currently, we don't need to copy the other members because they are
865     // for internal use only (not available from JS).
866   }
867 
868   bool IsComposing() const { return mRanges && mRanges->IsComposing(); }
869 
870   uint32_t TargetClauseOffset() const {
871     return mRanges ? mRanges->TargetClauseOffset() : 0;
872   }
873 
874   uint32_t TargetClauseLength() const {
875     uint32_t length = UINT32_MAX;
876     if (mRanges) {
877       length = mRanges->TargetClauseLength();
878     }
879     return length == UINT32_MAX ? mData.Length() : length;
880   }
881 
882   uint32_t RangeCount() const { return mRanges ? mRanges->Length() : 0; }
883 
884   bool CausesDOMTextEvent() const {
885     return mMessage == eCompositionChange || mMessage == eCompositionCommit ||
886            mMessage == eCompositionCommitAsIs;
887   }
888 
889   bool CausesDOMCompositionEndEvent() const {
890     return mMessage == eCompositionEnd || mMessage == eCompositionCommit ||
891            mMessage == eCompositionCommitAsIs;
892   }
893 
894   bool IsFollowedByCompositionEnd() const {
895     return IsFollowedByCompositionEnd(mOriginalMessage);
896   }
897 
898   static bool IsFollowedByCompositionEnd(EventMessage aEventMessage) {
899     return aEventMessage == eCompositionCommit ||
900            aEventMessage == eCompositionCommitAsIs;
901   }
902 };
903 
904 /******************************************************************************
905  * mozilla::WidgetQueryContentEvent
906  ******************************************************************************/
907 
908 class WidgetQueryContentEvent : public WidgetGUIEvent {
909  private:
910   friend class dom::PBrowserParent;
911   friend class dom::PBrowserChild;
912 
913   WidgetQueryContentEvent()
914       : mSucceeded(false),
915         mUseNativeLineBreak(true),
916         mWithFontRanges(false),
917         mNeedsToFlushLayout(true) {
918     MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
919   }
920 
921  public:
922   virtual WidgetQueryContentEvent* AsQueryContentEvent() override {
923     return this;
924   }
925 
926   WidgetQueryContentEvent(bool aIsTrusted, EventMessage aMessage,
927                           nsIWidget* aWidget)
928       : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eQueryContentEventClass),
929         mSucceeded(false),
930         mUseNativeLineBreak(true),
931         mWithFontRanges(false),
932         mNeedsToFlushLayout(true) {}
933 
934   WidgetQueryContentEvent(EventMessage aMessage,
935                           const WidgetQueryContentEvent& aOtherEvent)
936       : WidgetGUIEvent(aOtherEvent.IsTrusted(), aMessage,
937                        const_cast<nsIWidget*>(aOtherEvent.mWidget.get()),
938                        eQueryContentEventClass),
939         mSucceeded(false),
940         mUseNativeLineBreak(aOtherEvent.mUseNativeLineBreak),
941         mWithFontRanges(false),
942         mNeedsToFlushLayout(aOtherEvent.mNeedsToFlushLayout) {}
943 
944   virtual WidgetEvent* Duplicate() const override {
945     // This event isn't an internal event of any DOM event.
946     NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
947                  "WidgetQueryContentEvent needs to support Duplicate()");
948     MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
949   }
950 
951   struct Options final {
952     bool mUseNativeLineBreak;
953     bool mRelativeToInsertionPoint;
954 
955     explicit Options()
956         : mUseNativeLineBreak(true), mRelativeToInsertionPoint(false) {}
957 
958     explicit Options(const WidgetQueryContentEvent& aEvent)
959         : mUseNativeLineBreak(aEvent.mUseNativeLineBreak),
960           mRelativeToInsertionPoint(aEvent.mInput.mRelativeToInsertionPoint) {}
961   };
962 
963   void Init(const Options& aOptions) {
964     mUseNativeLineBreak = aOptions.mUseNativeLineBreak;
965     mInput.mRelativeToInsertionPoint = aOptions.mRelativeToInsertionPoint;
966     MOZ_ASSERT(mInput.IsValidEventMessage(mMessage));
967   }
968 
969   void InitForQueryTextContent(int64_t aOffset, uint32_t aLength,
970                                const Options& aOptions = Options()) {
971     NS_ASSERTION(mMessage == eQueryTextContent, "wrong initializer is called");
972     mInput.mOffset = aOffset;
973     mInput.mLength = aLength;
974     Init(aOptions);
975     MOZ_ASSERT(mInput.IsValidOffset());
976   }
977 
978   void InitForQueryCaretRect(int64_t aOffset,
979                              const Options& aOptions = Options()) {
980     NS_ASSERTION(mMessage == eQueryCaretRect, "wrong initializer is called");
981     mInput.mOffset = aOffset;
982     Init(aOptions);
983     MOZ_ASSERT(mInput.IsValidOffset());
984   }
985 
986   void InitForQueryTextRect(int64_t aOffset, uint32_t aLength,
987                             const Options& aOptions = Options()) {
988     NS_ASSERTION(mMessage == eQueryTextRect, "wrong initializer is called");
989     mInput.mOffset = aOffset;
990     mInput.mLength = aLength;
991     Init(aOptions);
992     MOZ_ASSERT(mInput.IsValidOffset());
993   }
994 
995   void InitForQuerySelectedText(SelectionType aSelectionType,
996                                 const Options& aOptions = Options()) {
997     MOZ_ASSERT(mMessage == eQuerySelectedText);
998     MOZ_ASSERT(aSelectionType != SelectionType::eNone);
999     mInput.mSelectionType = aSelectionType;
1000     Init(aOptions);
1001   }
1002 
1003   void InitForQueryDOMWidgetHittest(
1004       const mozilla::LayoutDeviceIntPoint& aPoint) {
1005     NS_ASSERTION(mMessage == eQueryDOMWidgetHittest,
1006                  "wrong initializer is called");
1007     mRefPoint = aPoint;
1008   }
1009 
1010   void InitForQueryTextRectArray(uint32_t aOffset, uint32_t aLength,
1011                                  const Options& aOptions = Options()) {
1012     NS_ASSERTION(mMessage == eQueryTextRectArray,
1013                  "wrong initializer is called");
1014     mInput.mOffset = aOffset;
1015     mInput.mLength = aLength;
1016     Init(aOptions);
1017   }
1018 
1019   bool NeedsToFlushLayout() const { return mNeedsToFlushLayout; }
1020 
1021   void RequestFontRanges() {
1022     NS_ASSERTION(mMessage == eQueryTextContent, "not querying text content");
1023     mWithFontRanges = true;
1024   }
1025 
1026   uint32_t GetSelectionStart(void) const {
1027     NS_ASSERTION(mMessage == eQuerySelectedText, "not querying selection");
1028     return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0);
1029   }
1030 
1031   uint32_t GetSelectionEnd(void) const {
1032     NS_ASSERTION(mMessage == eQuerySelectedText, "not querying selection");
1033     return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length());
1034   }
1035 
1036   mozilla::WritingMode GetWritingMode(void) const {
1037     NS_ASSERTION(mMessage == eQuerySelectedText ||
1038                      mMessage == eQueryCaretRect || mMessage == eQueryTextRect,
1039                  "not querying selection or text rect");
1040     return mReply.mWritingMode;
1041   }
1042 
1043   bool mSucceeded;
1044   bool mUseNativeLineBreak;
1045   bool mWithFontRanges;
1046   bool mNeedsToFlushLayout;
1047   struct Input final {
1048     uint32_t EndOffset() const {
1049       CheckedInt<uint32_t> endOffset = CheckedInt<uint32_t>(mOffset) + mLength;
1050       return NS_WARN_IF(!endOffset.isValid()) ? UINT32_MAX : endOffset.value();
1051     }
1052 
1053     int64_t mOffset;
1054     uint32_t mLength;
1055     SelectionType mSelectionType;
1056     // If mOffset is true, mOffset is relative to the start offset of
1057     // composition if there is, otherwise, the start of the first selection
1058     // range.
1059     bool mRelativeToInsertionPoint;
1060 
1061     Input()
1062         : mOffset(0),
1063           mLength(0),
1064           mSelectionType(SelectionType::eNormal),
1065           mRelativeToInsertionPoint(false) {}
1066 
1067     bool IsValidOffset() const {
1068       return mRelativeToInsertionPoint || mOffset >= 0;
1069     }
1070     bool IsValidEventMessage(EventMessage aEventMessage) const {
1071       if (!mRelativeToInsertionPoint) {
1072         return true;
1073       }
1074       switch (aEventMessage) {
1075         case eQueryTextContent:
1076         case eQueryCaretRect:
1077         case eQueryTextRect:
1078           return true;
1079         default:
1080           return false;
1081       }
1082     }
1083     bool MakeOffsetAbsolute(uint32_t aInsertionPointOffset) {
1084       if (NS_WARN_IF(!mRelativeToInsertionPoint)) {
1085         return true;
1086       }
1087       mRelativeToInsertionPoint = false;
1088       // If mOffset + aInsertionPointOffset becomes negative value,
1089       // we should assume the absolute offset is 0.
1090       if (mOffset < 0 && -mOffset > aInsertionPointOffset) {
1091         mOffset = 0;
1092         return true;
1093       }
1094       // Otherwise, we don't allow too large offset.
1095       CheckedInt<uint32_t> absOffset =
1096           CheckedInt<uint32_t>(mOffset) + aInsertionPointOffset;
1097       if (NS_WARN_IF(!absOffset.isValid())) {
1098         mOffset = UINT32_MAX;
1099         return false;
1100       }
1101       mOffset = absOffset.value();
1102       return true;
1103     }
1104   } mInput;
1105 
1106   struct Reply final {
1107     void* mContentsRoot;
1108     uint32_t mOffset;
1109     // mTentativeCaretOffset is used by only eQueryCharacterAtPoint.
1110     // This is the offset where caret would be if user clicked at the mRefPoint.
1111     uint32_t mTentativeCaretOffset;
1112     nsString mString;
1113     // mRect is used by eQueryTextRect, eQueryCaretRect, eQueryCharacterAtPoint
1114     // and eQueryEditorRect. The coordinates is system coordinates relative to
1115     // the top level widget of mFocusedWidget.  E.g., if a <xul:panel> which
1116     // is owned by a window has focused editor, the offset of mRect is relative
1117     // to the owner window, not the <xul:panel>.
1118     mozilla::LayoutDeviceIntRect mRect;
1119     // The return widget has the caret. This is set at all query events.
1120     nsIWidget* mFocusedWidget;
1121     // mozilla::WritingMode value at the end (focus) of the selection
1122     mozilla::WritingMode mWritingMode;
1123     // Used by eQuerySelectionAsTransferable
1124     nsCOMPtr<nsITransferable> mTransferable;
1125     // Used by eQueryTextContent with font ranges requested
1126     CopyableAutoTArray<mozilla::FontRange, 1> mFontRanges;
1127     // Used by eQueryTextRectArray
1128     CopyableTArray<mozilla::LayoutDeviceIntRect> mRectArray;
1129     // true if selection is reversed (end < start)
1130     bool mReversed;
1131     // true if the selection exists
1132     bool mHasSelection;
1133     // true if DOM element under mouse belongs to widget
1134     bool mWidgetIsHit;
1135 
1136     Reply()
1137         : mContentsRoot(nullptr),
1138           mOffset(NOT_FOUND),
1139           mTentativeCaretOffset(NOT_FOUND),
1140           mFocusedWidget(nullptr),
1141           mReversed(false),
1142           mHasSelection(false),
1143           mWidgetIsHit(false) {}
1144   } mReply;
1145 
1146   enum { NOT_FOUND = UINT32_MAX };
1147 
1148   // values of mComputedScrollAction
1149   enum { SCROLL_ACTION_NONE, SCROLL_ACTION_LINE, SCROLL_ACTION_PAGE };
1150 };
1151 
1152 /******************************************************************************
1153  * mozilla::WidgetSelectionEvent
1154  ******************************************************************************/
1155 
1156 class WidgetSelectionEvent : public WidgetGUIEvent {
1157  private:
1158   friend class mozilla::dom::PBrowserParent;
1159   friend class mozilla::dom::PBrowserChild;
1160 
1161   WidgetSelectionEvent()
1162       : mOffset(0),
1163         mLength(0),
1164         mReversed(false),
1165         mExpandToClusterBoundary(true),
1166         mSucceeded(false),
1167         mUseNativeLineBreak(true),
1168         mReason(nsISelectionListener::NO_REASON) {}
1169 
1170  public:
1171   virtual WidgetSelectionEvent* AsSelectionEvent() override { return this; }
1172 
1173   WidgetSelectionEvent(bool aIsTrusted, EventMessage aMessage,
1174                        nsIWidget* aWidget)
1175       : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eSelectionEventClass),
1176         mOffset(0),
1177         mLength(0),
1178         mReversed(false),
1179         mExpandToClusterBoundary(true),
1180         mSucceeded(false),
1181         mUseNativeLineBreak(true),
1182         mReason(nsISelectionListener::NO_REASON) {}
1183 
1184   virtual WidgetEvent* Duplicate() const override {
1185     // This event isn't an internal event of any DOM event.
1186     NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
1187                  "WidgetSelectionEvent needs to support Duplicate()");
1188     MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()");
1189     return nullptr;
1190   }
1191 
1192   // Start offset of selection
1193   uint32_t mOffset;
1194   // Length of selection
1195   uint32_t mLength;
1196   // Selection "anchor" should be in front
1197   bool mReversed;
1198   // Cluster-based or character-based
1199   bool mExpandToClusterBoundary;
1200   // true if setting selection succeeded.
1201   bool mSucceeded;
1202   // true if native line breaks are used for mOffset and mLength
1203   bool mUseNativeLineBreak;
1204   // Fennec provides eSetSelection reason codes for downstream
1205   // use in AccessibleCaret visibility logic.
1206   int16_t mReason;
1207 };
1208 
1209 /******************************************************************************
1210  * mozilla::InternalEditorInputEvent
1211  ******************************************************************************/
1212 
1213 class InternalEditorInputEvent : public InternalUIEvent {
1214  private:
1215   InternalEditorInputEvent()
1216       : mData(VoidString()),
1217         mInputType(EditorInputType::eUnknown),
1218         mIsComposing(false) {}
1219 
1220  public:
1221   virtual InternalEditorInputEvent* AsEditorInputEvent() override {
1222     return this;
1223   }
1224 
1225   InternalEditorInputEvent(bool aIsTrusted, EventMessage aMessage,
1226                            nsIWidget* aWidget = nullptr)
1227       : InternalUIEvent(aIsTrusted, aMessage, aWidget, eEditorInputEventClass),
1228         mData(VoidString()),
1229         mInputType(EditorInputType::eUnknown) {}
1230 
1231   virtual WidgetEvent* Duplicate() const override {
1232     MOZ_ASSERT(mClass == eEditorInputEventClass,
1233                "Duplicate() must be overridden by sub class");
1234     // Not copying widget, it is a weak reference.
1235     InternalEditorInputEvent* result =
1236         new InternalEditorInputEvent(false, mMessage, nullptr);
1237     result->AssignEditorInputEventData(*this, true);
1238     result->mFlags = mFlags;
1239     return result;
1240   }
1241 
1242   nsString mData;
1243   RefPtr<dom::DataTransfer> mDataTransfer;
1244   OwningNonNullStaticRangeArray mTargetRanges;
1245 
1246   EditorInputType mInputType;
1247 
1248   bool mIsComposing;
1249 
1250   void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent,
1251                                   bool aCopyTargets) {
1252     AssignUIEventData(aEvent, aCopyTargets);
1253 
1254     mData = aEvent.mData;
1255     mDataTransfer = aEvent.mDataTransfer;
1256     mTargetRanges = aEvent.mTargetRanges.Clone();
1257     mInputType = aEvent.mInputType;
1258     mIsComposing = aEvent.mIsComposing;
1259   }
1260 
1261   void GetDOMInputTypeName(nsAString& aInputTypeName) {
1262     GetDOMInputTypeName(mInputType, aInputTypeName);
1263   }
1264   static void GetDOMInputTypeName(EditorInputType aInputType,
1265                                   nsAString& aInputTypeName);
1266   static EditorInputType GetEditorInputType(const nsAString& aInputType);
1267 
1268   static void Shutdown();
1269 
1270  private:
1271   static const char16_t* const kInputTypeNames[];
1272   typedef nsDataHashtable<nsStringHashKey, EditorInputType> InputTypeHashtable;
1273   static InputTypeHashtable* sInputTypeHashtable;
1274 };
1275 
1276 }  // namespace mozilla
1277 
1278 #endif  // mozilla_TextEvents_h__
1279