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/EventForwards.h" // for KeyNameIndex, temporarily
15 #include "mozilla/TextRange.h"
16 #include "mozilla/FontRange.h"
17 #include "nsCOMPtr.h"
18 #include "nsIDOMKeyEvent.h"
19 #include "nsISelectionController.h"
20 #include "nsISelectionListener.h"
21 #include "nsITransferable.h"
22 #include "nsRect.h"
23 #include "nsStringGlue.h"
24 #include "nsTArray.h"
25 #include "WritingModes.h"
26 
27 class nsStringHashKey;
28 template<class, class> class nsDataHashtable;
29 
30 /******************************************************************************
31  * virtual keycode values
32  ******************************************************************************/
33 
34 enum
35 {
36 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode,
37 #include "mozilla/VirtualKeyCodeList.h"
38 #undef NS_DEFINE_VK
39   NS_VK_UNKNOWN = 0xFF
40 };
41 
42 namespace mozilla {
43 
44 const nsCString GetDOMKeyCodeName(uint32_t aKeyCode);
45 
46 namespace dom {
47   class PBrowserParent;
48   class PBrowserChild;
49 } // namespace dom
50 namespace plugins {
51   class PPluginInstanceChild;
52 } // namespace plugins
53 
54 /******************************************************************************
55  * mozilla::AlternativeCharCode
56  *
57  * This stores alternative charCode values of a key event with some modifiers.
58  * The stored values proper for testing shortcut key or access key.
59  ******************************************************************************/
60 
61 struct AlternativeCharCode
62 {
AlternativeCharCodeAlternativeCharCode63   AlternativeCharCode() :
64     mUnshiftedCharCode(0), mShiftedCharCode(0)
65   {
66   }
AlternativeCharCodeAlternativeCharCode67   AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode) :
68     mUnshiftedCharCode(aUnshiftedCharCode), mShiftedCharCode(aShiftedCharCode)
69   {
70   }
71   uint32_t mUnshiftedCharCode;
72   uint32_t mShiftedCharCode;
73 };
74 
75 /******************************************************************************
76  * mozilla::ShortcutKeyCandidate
77  *
78  * This stores a candidate of shortcut key combination.
79  ******************************************************************************/
80 
81 struct ShortcutKeyCandidate
82 {
ShortcutKeyCandidateShortcutKeyCandidate83   ShortcutKeyCandidate(uint32_t aCharCode, bool aIgnoreShift)
84     : mCharCode(aCharCode)
85     , mIgnoreShift(aIgnoreShift)
86   {
87   }
88   // The mCharCode value which must match keyboard shortcut definition.
89   uint32_t mCharCode;
90   // true if Shift state can be ignored.  Otherwise, Shift key state must
91   // match keyboard shortcut definition.
92   bool mIgnoreShift;
93 };
94 
95 /******************************************************************************
96  * mozilla::WidgetKeyboardEvent
97  ******************************************************************************/
98 
99 class WidgetKeyboardEvent : public WidgetInputEvent
100 {
101 private:
102   friend class dom::PBrowserParent;
103   friend class dom::PBrowserChild;
104 
105 protected:
WidgetKeyboardEvent()106   WidgetKeyboardEvent()
107     : mNativeKeyEvent(nullptr)
108     , mKeyCode(0)
109     , mCharCode(0)
110     , mPseudoCharCode(0)
111     , mLocation(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
112     , mAccessKeyForwardedToChild(false)
113     , mUniqueId(0)
114 #ifdef XP_MACOSX
115     , mNativeModifierFlags(0)
116     , mNativeKeyCode(0)
117 #endif // #ifdef XP_MACOSX
118     , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
119     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
120     , mInputMethodAppState(eNotHandled)
121     , mIsChar(false)
122     , mIsRepeat(false)
123     , mIsComposing(false)
124     , mIsReserved(false)
125     , mIsSynthesizedByTIP(false)
126   {
127   }
128 
129 public:
AsKeyboardEvent()130   virtual WidgetKeyboardEvent* AsKeyboardEvent() override { return this; }
131 
132   WidgetKeyboardEvent(bool aIsTrusted, EventMessage aMessage,
133                       nsIWidget* aWidget,
134                       EventClassID aEventClassID = eKeyboardEventClass)
WidgetInputEvent(aIsTrusted,aMessage,aWidget,aEventClassID)135     : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID)
136     , mNativeKeyEvent(nullptr)
137     , mKeyCode(0)
138     , mCharCode(0)
139     , mPseudoCharCode(0)
140     , mLocation(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
141     , mAccessKeyForwardedToChild(false)
142     , mUniqueId(0)
143 #ifdef XP_MACOSX
144     , mNativeModifierFlags(0)
145     , mNativeKeyCode(0)
146 #endif // #ifdef XP_MACOSX
147     , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
148     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
149     , mInputMethodAppState(eNotHandled)
150     , mIsChar(false)
151     , mIsRepeat(false)
152     , mIsComposing(false)
153     , mIsReserved(false)
154     , mIsSynthesizedByTIP(false)
155   {
156     // If this is a keyboard event on a plugin, it shouldn't fired on content.
157     mFlags.mOnlySystemGroupDispatchInContent =
158       mFlags.mNoCrossProcessBoundaryForwarding = IsKeyEventOnPlugin();
159   }
160 
IsKeyDownOrKeyDownOnPlugin(EventMessage aMessage)161   static bool IsKeyDownOrKeyDownOnPlugin(EventMessage aMessage)
162   {
163     return aMessage == eKeyDown || aMessage == eKeyDownOnPlugin;
164   }
IsKeyDownOrKeyDownOnPlugin()165   bool IsKeyDownOrKeyDownOnPlugin() const
166   {
167     return IsKeyDownOrKeyDownOnPlugin(mMessage);
168   }
IsKeyUpOrKeyUpOnPlugin(EventMessage aMessage)169   static bool IsKeyUpOrKeyUpOnPlugin(EventMessage aMessage)
170   {
171     return aMessage == eKeyUp || aMessage == eKeyUpOnPlugin;
172   }
IsKeyUpOrKeyUpOnPlugin()173   bool IsKeyUpOrKeyUpOnPlugin() const
174   {
175     return IsKeyUpOrKeyUpOnPlugin(mMessage);
176   }
IsKeyEventOnPlugin(EventMessage aMessage)177   static bool IsKeyEventOnPlugin(EventMessage aMessage)
178   {
179     return aMessage == eKeyDownOnPlugin || aMessage == eKeyUpOnPlugin;
180   }
IsKeyEventOnPlugin()181   bool IsKeyEventOnPlugin() const
182   {
183     return IsKeyEventOnPlugin(mMessage);
184   }
185 
Duplicate()186   virtual WidgetEvent* Duplicate() const override
187   {
188     MOZ_ASSERT(mClass == eKeyboardEventClass,
189                "Duplicate() must be overridden by sub class");
190     // Not copying widget, it is a weak reference.
191     WidgetKeyboardEvent* result =
192       new WidgetKeyboardEvent(false, mMessage, nullptr);
193     result->AssignKeyEventData(*this, true);
194     result->mFlags = mFlags;
195     return result;
196   }
197 
198   // OS translated Unicode chars which are used for accesskey and accelkey
199   // handling. The handlers will try from first character to last character.
200   nsTArray<AlternativeCharCode> mAlternativeCharCodes;
201   // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING.
202   nsString mKeyValue;
203   // DOM KeyboardEvent.code only when mCodeNameIndex is
204   // CODE_NAME_INDEX_USE_STRING.
205   nsString mCodeValue;
206 
207 #ifdef XP_MACOSX
208   // Values given by a native NSEvent, for use with Cocoa NPAPI plugins.
209   nsString mNativeCharacters;
210   nsString mNativeCharactersIgnoringModifiers;
211   // If this is non-empty, create a text event for plugins instead of a
212   // keyboard event.
213   nsString mPluginTextEventString;
214 #endif // #ifdef XP_MACOSX
215 
216   // OS-specific native event can optionally be preserved
217   void* mNativeKeyEvent;
218   // A DOM keyCode value or 0.  If a keypress event whose mCharCode is 0, this
219   // should be 0.
220   uint32_t mKeyCode;
221   // If the instance is a keypress event of a printable key, this is a UTF-16
222   // value of the key.  Otherwise, 0.  This value must not be a control
223   // character when some modifiers are active.  Then, this value should be an
224   // unmodified value except Shift and AltGr.
225   uint32_t mCharCode;
226   // mPseudoCharCode is valid only when mMessage is an eKeyDown event.
227   // This stores mCharCode value of keypress event which is fired with same
228   // key value and same modifier state.
229   uint32_t mPseudoCharCode;
230   // One of nsIDOMKeyEvent::DOM_KEY_LOCATION_*
231   uint32_t mLocation;
232   // True if accesskey handling was forwarded to the child via
233   // TabParent::HandleAccessKey. In this case, parent process menu access key
234   // handling should be delayed until it is determined that there exists no
235   // overriding access key in the content process.
236   bool mAccessKeyForwardedToChild;
237   // Unique id associated with a keydown / keypress event. Used in identifing
238   // keypress events for removal from async event dispatch queue in metrofx
239   // after preventDefault is called on keydown events. It's ok if this wraps
240   // over long periods.
241   uint32_t mUniqueId;
242 
243 #ifdef XP_MACOSX
244   // Values given by a native NSEvent, for use with Cocoa NPAPI plugins.
245   uint32_t mNativeModifierFlags;
246   uint16_t mNativeKeyCode;
247 #endif // #ifdef XP_MACOSX
248 
249   // DOM KeyboardEvent.key
250   KeyNameIndex mKeyNameIndex;
251   // DOM KeyboardEvent.code
252   CodeNameIndex mCodeNameIndex;
253   // Indicates that the event is being handled by input method app
254   typedef uint8_t InputMethodAppStateType;
255   enum InputMethodAppState : InputMethodAppStateType
256   {
257     eNotHandled, // not yet handled by intput method app
258     eHandling,   // being handled by intput method app
259     eHandled     // handled by input method app
260   };
261   InputMethodAppState mInputMethodAppState;
262 
263   // Indicates whether the event signifies a printable character
264   bool mIsChar;
265   // Indicates whether the event is generated by auto repeat or not.
266   // if this is keyup event, always false.
267   bool mIsRepeat;
268   // Indicates whether the event is generated during IME (or deadkey)
269   // composition.  This is initialized by EventStateManager.  So, key event
270   // dispatchers don't need to initialize this.
271   bool mIsComposing;
272   // Indicates if the key combination is reserved by chrome.  This is set by
273   // nsXBLWindowKeyHandler at capturing phase of the default event group.
274   bool mIsReserved;
275   // Indicates whether the event is synthesized from Text Input Processor
276   // or an actual event from nsAppShell.
277   bool mIsSynthesizedByTIP;
278 
279   // If the key should cause keypress events, this returns true.
280   // Otherwise, false.
281   bool ShouldCauseKeypressEvents() const;
282 
283   // mCharCode value of non-eKeyPress events is always 0.  However, if
284   // non-eKeyPress event has one or more alternative char code values,
285   // its first item should be the mCharCode value of following eKeyPress event.
286   // PseudoCharCode() returns mCharCode value for eKeyPress event,
287   // the first alternative char code value of non-eKeyPress event or 0.
PseudoCharCode()288   uint32_t PseudoCharCode() const
289   {
290     return mMessage == eKeyPress ? mCharCode : mPseudoCharCode;
291   }
SetCharCode(uint32_t aCharCode)292   void SetCharCode(uint32_t aCharCode)
293   {
294     if (mMessage == eKeyPress) {
295       mCharCode = aCharCode;
296     } else {
297       mPseudoCharCode = aCharCode;
298     }
299   }
300 
GetDOMKeyName(nsAString & aKeyName)301   void GetDOMKeyName(nsAString& aKeyName)
302   {
303     if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
304       aKeyName = mKeyValue;
305       return;
306     }
307     GetDOMKeyName(mKeyNameIndex, aKeyName);
308   }
GetDOMCodeName(nsAString & aCodeName)309   void GetDOMCodeName(nsAString& aCodeName)
310   {
311     if (mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
312       aCodeName = mCodeValue;
313       return;
314     }
315     GetDOMCodeName(mCodeNameIndex, aCodeName);
316   }
317 
IsModifierKeyEvent()318   bool IsModifierKeyEvent() const
319   {
320     return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE;
321   }
322 
323   /**
324    * Get the candidates for shortcut key.
325    *
326    * @param aCandidates [out] the candidate shortcut key combination list.
327    *                          the first item is most preferred.
328    */
329   void GetShortcutKeyCandidates(ShortcutKeyCandidateArray& aCandidates);
330 
331   /**
332    * Get the candidates for access key.
333    *
334    * @param aCandidates [out] the candidate access key list.
335    *                          the first item is most preferred.
336    */
337   void GetAccessKeyCandidates(nsTArray<uint32_t>& aCandidates);
338 
339   static void Shutdown();
340 
341   /**
342    * ComputeLocationFromCodeValue() returns one of .mLocation value
343    * (nsIDOMKeyEvent::DOM_KEY_LOCATION_*) which is the most preferred value
344    * for the specified specified code value.
345    */
346   static uint32_t ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex);
347 
348   /**
349    * ComputeKeyCodeFromKeyNameIndex() return a .mKeyCode value which can be
350    * mapped from the specified key value.  Note that this returns 0 if the
351    * key name index is KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING.
352    * This means that this method is useful only for non-printable keys.
353    */
354   static uint32_t ComputeKeyCodeFromKeyNameIndex(KeyNameIndex aKeyNameIndex);
355 
356   /**
357    * GetModifierForKeyName() returns a value of Modifier which is activated
358    * by the aKeyNameIndex.
359    */
360   static Modifier GetModifierForKeyName(KeyNameIndex aKeyNameIndex);
361 
362   /**
363    * IsLockableModifier() returns true if aKeyNameIndex is a lockable modifier
364    * key such as CapsLock and NumLock.
365    */
366   static bool IsLockableModifier(KeyNameIndex aKeyNameIndex);
367 
368   static void GetDOMKeyName(KeyNameIndex aKeyNameIndex,
369                             nsAString& aKeyName);
370   static void GetDOMCodeName(CodeNameIndex aCodeNameIndex,
371                              nsAString& aCodeName);
372 
373   static KeyNameIndex GetKeyNameIndex(const nsAString& aKeyValue);
374   static CodeNameIndex GetCodeNameIndex(const nsAString& aCodeValue);
375 
376   static const char* GetCommandStr(Command aCommand);
377 
AssignKeyEventData(const WidgetKeyboardEvent & aEvent,bool aCopyTargets)378   void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets)
379   {
380     AssignInputEventData(aEvent, aCopyTargets);
381 
382     mKeyCode = aEvent.mKeyCode;
383     mCharCode = aEvent.mCharCode;
384     mPseudoCharCode = aEvent.mPseudoCharCode;
385     mLocation = aEvent.mLocation;
386     mAlternativeCharCodes = aEvent.mAlternativeCharCodes;
387     mIsChar = aEvent.mIsChar;
388     mIsRepeat = aEvent.mIsRepeat;
389     mIsComposing = aEvent.mIsComposing;
390     mIsReserved = aEvent.mIsReserved;
391     mAccessKeyForwardedToChild = aEvent.mAccessKeyForwardedToChild;
392     mKeyNameIndex = aEvent.mKeyNameIndex;
393     mCodeNameIndex = aEvent.mCodeNameIndex;
394     mKeyValue = aEvent.mKeyValue;
395     mCodeValue = aEvent.mCodeValue;
396     // Don't copy mNativeKeyEvent because it may be referred after its instance
397     // is destroyed.
398     mNativeKeyEvent = nullptr;
399     mUniqueId = aEvent.mUniqueId;
400 #ifdef XP_MACOSX
401     mNativeKeyCode = aEvent.mNativeKeyCode;
402     mNativeModifierFlags = aEvent.mNativeModifierFlags;
403     mNativeCharacters.Assign(aEvent.mNativeCharacters);
404     mNativeCharactersIgnoringModifiers.
405       Assign(aEvent.mNativeCharactersIgnoringModifiers);
406     mPluginTextEventString.Assign(aEvent.mPluginTextEventString);
407 #endif
408     mInputMethodAppState = aEvent.mInputMethodAppState;
409     mIsSynthesizedByTIP = aEvent.mIsSynthesizedByTIP;
410   }
411 
412 private:
413   static const char16_t* const kKeyNames[];
414   static const char16_t* const kCodeNames[];
415   typedef nsDataHashtable<nsStringHashKey,
416                           KeyNameIndex> KeyNameIndexHashtable;
417   typedef nsDataHashtable<nsStringHashKey,
418                           CodeNameIndex> CodeNameIndexHashtable;
419   static KeyNameIndexHashtable* sKeyNameIndexHashtable;
420   static CodeNameIndexHashtable* sCodeNameIndexHashtable;
421 };
422 
423 
424 /******************************************************************************
425  * mozilla::InternalBeforeAfterKeyboardEvent
426  *
427  * This is extended from WidgetKeyboardEvent and is mapped to DOM event
428  * "BeforeAfterKeyboardEvent".
429  *
430  * Event mMessage: eBeforeKeyDown
431  *                 eBeforeKeyUp
432  *                 eAfterKeyDown
433  *                 eAfterKeyUp
434  ******************************************************************************/
435 class InternalBeforeAfterKeyboardEvent : public WidgetKeyboardEvent
436 {
437 private:
438   friend class dom::PBrowserParent;
439   friend class dom::PBrowserChild;
440 
InternalBeforeAfterKeyboardEvent()441   InternalBeforeAfterKeyboardEvent()
442   {
443   }
444 
445 public:
446   // Extra member for InternalBeforeAfterKeyboardEvent. Indicates whether
447   // default actions of keydown/keyup event is prevented.
448   Nullable<bool> mEmbeddedCancelled;
449 
AsBeforeAfterKeyboardEvent()450   virtual InternalBeforeAfterKeyboardEvent* AsBeforeAfterKeyboardEvent() override
451   {
452     return this;
453   }
454 
InternalBeforeAfterKeyboardEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget)455   InternalBeforeAfterKeyboardEvent(bool aIsTrusted, EventMessage aMessage,
456                                    nsIWidget* aWidget)
457     : WidgetKeyboardEvent(aIsTrusted, aMessage, aWidget,
458                           eBeforeAfterKeyboardEventClass)
459   {
460   }
461 
Duplicate()462   virtual WidgetEvent* Duplicate() const override
463   {
464     MOZ_ASSERT(mClass == eBeforeAfterKeyboardEventClass,
465                "Duplicate() must be overridden by sub class");
466     // Not copying widget, it is a weak reference.
467     InternalBeforeAfterKeyboardEvent* result =
468       new InternalBeforeAfterKeyboardEvent(false, mMessage, nullptr);
469     result->AssignBeforeAfterKeyEventData(*this, true);
470     result->mFlags = mFlags;
471     return result;
472   }
473 
AssignBeforeAfterKeyEventData(const InternalBeforeAfterKeyboardEvent & aEvent,bool aCopyTargets)474   void AssignBeforeAfterKeyEventData(
475          const InternalBeforeAfterKeyboardEvent& aEvent,
476          bool aCopyTargets)
477   {
478     AssignKeyEventData(aEvent, aCopyTargets);
479     mEmbeddedCancelled = aEvent.mEmbeddedCancelled;
480   }
481 
AssignBeforeAfterKeyEventData(const WidgetKeyboardEvent & aEvent,bool aCopyTargets)482   void AssignBeforeAfterKeyEventData(
483          const WidgetKeyboardEvent& aEvent,
484          bool aCopyTargets)
485   {
486     AssignKeyEventData(aEvent, aCopyTargets);
487   }
488 };
489 
490 /******************************************************************************
491  * mozilla::WidgetCompositionEvent
492  ******************************************************************************/
493 
494 class WidgetCompositionEvent : public WidgetGUIEvent
495 {
496 private:
497   friend class mozilla::dom::PBrowserParent;
498   friend class mozilla::dom::PBrowserChild;
499 
WidgetCompositionEvent()500   WidgetCompositionEvent()
501   {
502   }
503 
504 public:
AsCompositionEvent()505   virtual WidgetCompositionEvent* AsCompositionEvent() override
506   {
507     return this;
508   }
509 
WidgetCompositionEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget)510   WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage,
511                          nsIWidget* aWidget)
512     : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass)
513     , mNativeIMEContext(aWidget)
514     , mOriginalMessage(eVoidEvent)
515   {
516   }
517 
Duplicate()518   virtual WidgetEvent* Duplicate() const override
519   {
520     MOZ_ASSERT(mClass == eCompositionEventClass,
521                "Duplicate() must be overridden by sub class");
522     // Not copying widget, it is a weak reference.
523     WidgetCompositionEvent* result =
524       new WidgetCompositionEvent(false, mMessage, nullptr);
525     result->AssignCompositionEventData(*this, true);
526     result->mFlags = mFlags;
527     return result;
528   }
529 
530   // The composition string or the commit string.  If the instance is a
531   // compositionstart event, this is initialized with selected text by
532   // TextComposition automatically.
533   nsString mData;
534 
535   RefPtr<TextRangeArray> mRanges;
536 
537   // mNativeIMEContext stores the native IME context which causes the
538   // composition event.
539   widget::NativeIMEContext mNativeIMEContext;
540 
541   // If the instance is a clone of another event, mOriginalMessage stores
542   // the another event's mMessage.
543   EventMessage mOriginalMessage;
544 
AssignCompositionEventData(const WidgetCompositionEvent & aEvent,bool aCopyTargets)545   void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
546                                   bool aCopyTargets)
547   {
548     AssignGUIEventData(aEvent, aCopyTargets);
549 
550     mData = aEvent.mData;
551     mOriginalMessage = aEvent.mOriginalMessage;
552     mRanges = aEvent.mRanges;
553 
554     // Currently, we don't need to copy the other members because they are
555     // for internal use only (not available from JS).
556   }
557 
IsComposing()558   bool IsComposing() const
559   {
560     return mRanges && mRanges->IsComposing();
561   }
562 
TargetClauseOffset()563   uint32_t TargetClauseOffset() const
564   {
565     return mRanges ? mRanges->TargetClauseOffset() : 0;
566   }
567 
TargetClauseLength()568   uint32_t TargetClauseLength() const
569   {
570     uint32_t length = UINT32_MAX;
571     if (mRanges) {
572       length = mRanges->TargetClauseLength();
573     }
574     return length == UINT32_MAX ? mData.Length() : length;
575   }
576 
RangeCount()577   uint32_t RangeCount() const
578   {
579     return mRanges ? mRanges->Length() : 0;
580   }
581 
CausesDOMTextEvent()582   bool CausesDOMTextEvent() const
583   {
584     return mMessage == eCompositionChange ||
585            mMessage == eCompositionCommit ||
586            mMessage == eCompositionCommitAsIs;
587   }
588 
CausesDOMCompositionEndEvent()589   bool CausesDOMCompositionEndEvent() const
590   {
591     return mMessage == eCompositionEnd ||
592            mMessage == eCompositionCommit ||
593            mMessage == eCompositionCommitAsIs;
594   }
595 
IsFollowedByCompositionEnd()596   bool IsFollowedByCompositionEnd() const
597   {
598     return IsFollowedByCompositionEnd(mOriginalMessage);
599   }
600 
IsFollowedByCompositionEnd(EventMessage aEventMessage)601   static bool IsFollowedByCompositionEnd(EventMessage aEventMessage)
602   {
603     return aEventMessage == eCompositionCommit ||
604            aEventMessage == eCompositionCommitAsIs;
605   }
606 };
607 
608 /******************************************************************************
609  * mozilla::WidgetQueryContentEvent
610  ******************************************************************************/
611 
612 class WidgetQueryContentEvent : public WidgetGUIEvent
613 {
614 private:
615   friend class dom::PBrowserParent;
616   friend class dom::PBrowserChild;
617 
WidgetQueryContentEvent()618   WidgetQueryContentEvent()
619     : mSucceeded(false)
620     , mUseNativeLineBreak(true)
621     , mWithFontRanges(false)
622   {
623     MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
624   }
625 
626 public:
AsQueryContentEvent()627   virtual WidgetQueryContentEvent* AsQueryContentEvent() override
628   {
629     return this;
630   }
631 
WidgetQueryContentEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget)632   WidgetQueryContentEvent(bool aIsTrusted, EventMessage aMessage,
633                           nsIWidget* aWidget)
634     : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eQueryContentEventClass)
635     , mSucceeded(false)
636     , mUseNativeLineBreak(true)
637     , mWithFontRanges(false)
638   {
639   }
640 
WidgetQueryContentEvent(EventMessage aMessage,const WidgetQueryContentEvent & aOtherEvent)641   WidgetQueryContentEvent(EventMessage aMessage,
642                           const WidgetQueryContentEvent& aOtherEvent)
643     : WidgetGUIEvent(aOtherEvent.IsTrusted(), aMessage,
644                      const_cast<nsIWidget*>(aOtherEvent.mWidget.get()),
645                      eQueryContentEventClass)
646     , mSucceeded(false)
647     , mUseNativeLineBreak(aOtherEvent.mUseNativeLineBreak)
648     , mWithFontRanges(false)
649   {
650   }
651 
Duplicate()652   virtual WidgetEvent* Duplicate() const override
653   {
654     // This event isn't an internal event of any DOM event.
655     NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
656       "WidgetQueryContentEvent needs to support Duplicate()");
657     MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
658   }
659 
660   struct Options final
661   {
662     bool mUseNativeLineBreak;
663     bool mRelativeToInsertionPoint;
664 
Optionsfinal665     explicit Options()
666       : mUseNativeLineBreak(true)
667       , mRelativeToInsertionPoint(false)
668     {
669     }
670 
Optionsfinal671     explicit Options(const WidgetQueryContentEvent& aEvent)
672       : mUseNativeLineBreak(aEvent.mUseNativeLineBreak)
673       , mRelativeToInsertionPoint(aEvent.mInput.mRelativeToInsertionPoint)
674     {
675     }
676   };
677 
Init(const Options & aOptions)678   void Init(const Options& aOptions)
679   {
680     mUseNativeLineBreak = aOptions.mUseNativeLineBreak;
681     mInput.mRelativeToInsertionPoint = aOptions.mRelativeToInsertionPoint;
682     MOZ_ASSERT(mInput.IsValidEventMessage(mMessage));
683   }
684 
685   void InitForQueryTextContent(int64_t aOffset, uint32_t aLength,
686                                const Options& aOptions = Options())
687   {
688     NS_ASSERTION(mMessage == eQueryTextContent,
689                  "wrong initializer is called");
690     mInput.mOffset = aOffset;
691     mInput.mLength = aLength;
692     Init(aOptions);
693     MOZ_ASSERT(mInput.IsValidOffset());
694   }
695 
696   void InitForQueryCaretRect(int64_t aOffset,
697                              const Options& aOptions = Options())
698   {
699     NS_ASSERTION(mMessage == eQueryCaretRect,
700                  "wrong initializer is called");
701     mInput.mOffset = aOffset;
702     Init(aOptions);
703     MOZ_ASSERT(mInput.IsValidOffset());
704   }
705 
706   void InitForQueryTextRect(int64_t aOffset, uint32_t aLength,
707                             const Options& aOptions = Options())
708   {
709     NS_ASSERTION(mMessage == eQueryTextRect,
710                  "wrong initializer is called");
711     mInput.mOffset = aOffset;
712     mInput.mLength = aLength;
713     Init(aOptions);
714     MOZ_ASSERT(mInput.IsValidOffset());
715   }
716 
717   void InitForQuerySelectedText(SelectionType aSelectionType,
718                                 const Options& aOptions = Options())
719   {
720     MOZ_ASSERT(mMessage == eQuerySelectedText);
721     MOZ_ASSERT(aSelectionType != SelectionType::eNone);
722     mInput.mSelectionType = aSelectionType;
723     Init(aOptions);
724   }
725 
InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint & aPoint)726   void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint)
727   {
728     NS_ASSERTION(mMessage == eQueryDOMWidgetHittest,
729                  "wrong initializer is called");
730     mRefPoint = aPoint;
731   }
732 
733   void InitForQueryTextRectArray(uint32_t aOffset, uint32_t aLength,
734                                  const Options& aOptions = Options())
735   {
736     NS_ASSERTION(mMessage == eQueryTextRectArray,
737                  "wrong initializer is called");
738     mInput.mOffset = aOffset;
739     mInput.mLength = aLength;
740     Init(aOptions);
741   }
742 
RequestFontRanges()743   void RequestFontRanges()
744   {
745     NS_ASSERTION(mMessage == eQueryTextContent,
746                  "not querying text content");
747     mWithFontRanges = true;
748   }
749 
GetSelectionStart(void)750   uint32_t GetSelectionStart(void) const
751   {
752     NS_ASSERTION(mMessage == eQuerySelectedText,
753                  "not querying selection");
754     return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0);
755   }
756 
GetSelectionEnd(void)757   uint32_t GetSelectionEnd(void) const
758   {
759     NS_ASSERTION(mMessage == eQuerySelectedText,
760                  "not querying selection");
761     return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length());
762   }
763 
GetWritingMode(void)764   mozilla::WritingMode GetWritingMode(void) const
765   {
766     NS_ASSERTION(mMessage == eQuerySelectedText ||
767                  mMessage == eQueryCaretRect ||
768                  mMessage == eQueryTextRect,
769                  "not querying selection or text rect");
770     return mReply.mWritingMode;
771   }
772 
773   bool mSucceeded;
774   bool mUseNativeLineBreak;
775   bool mWithFontRanges;
776   struct Input final
777   {
EndOffsetfinal778     uint32_t EndOffset() const
779     {
780       CheckedInt<uint32_t> endOffset =
781         CheckedInt<uint32_t>(mOffset) + mLength;
782       return NS_WARN_IF(!endOffset.isValid()) ? UINT32_MAX : endOffset.value();
783     }
784 
785     int64_t mOffset;
786     uint32_t mLength;
787     SelectionType mSelectionType;
788     // If mOffset is true, mOffset is relative to the start offset of
789     // composition if there is, otherwise, the start of the first selection
790     // range.
791     bool mRelativeToInsertionPoint;
792 
Inputfinal793     Input()
794       : mOffset(0)
795       , mLength(0)
796       , mSelectionType(SelectionType::eNormal)
797       , mRelativeToInsertionPoint(false)
798     {
799     }
800 
IsValidOffsetfinal801     bool IsValidOffset() const
802     {
803       return mRelativeToInsertionPoint || mOffset >= 0;
804     }
IsValidEventMessagefinal805     bool IsValidEventMessage(EventMessage aEventMessage) const
806     {
807       if (!mRelativeToInsertionPoint) {
808         return true;
809       }
810       switch (aEventMessage) {
811         case eQueryTextContent:
812         case eQueryCaretRect:
813         case eQueryTextRect:
814           return true;
815         default:
816           return false;
817       }
818     }
MakeOffsetAbsolutefinal819     bool MakeOffsetAbsolute(uint32_t aInsertionPointOffset)
820     {
821       if (NS_WARN_IF(!mRelativeToInsertionPoint)) {
822         return true;
823       }
824       mRelativeToInsertionPoint = false;
825       // If mOffset + aInsertionPointOffset becomes negative value,
826       // we should assume the absolute offset is 0.
827       if (mOffset < 0 && -mOffset > aInsertionPointOffset) {
828         mOffset = 0;
829         return true;
830       }
831       // Otherwise, we don't allow too large offset.
832       CheckedInt<uint32_t> absOffset = mOffset + aInsertionPointOffset;
833       if (NS_WARN_IF(!absOffset.isValid())) {
834         mOffset = UINT32_MAX;
835         return false;
836       }
837       mOffset = absOffset.value();
838       return true;
839     }
840   } mInput;
841 
842   struct Reply final
843   {
844     void* mContentsRoot;
845     uint32_t mOffset;
846     // mTentativeCaretOffset is used by only eQueryCharacterAtPoint.
847     // This is the offset where caret would be if user clicked at the mRefPoint.
848     uint32_t mTentativeCaretOffset;
849     nsString mString;
850     // mRect is used by eQueryTextRect, eQueryCaretRect, eQueryCharacterAtPoint
851     // and eQueryEditorRect. The coordinates is system coordinates relative to
852     // the top level widget of mFocusedWidget.  E.g., if a <xul:panel> which
853     // is owned by a window has focused editor, the offset of mRect is relative
854     // to the owner window, not the <xul:panel>.
855     mozilla::LayoutDeviceIntRect mRect;
856     // The return widget has the caret. This is set at all query events.
857     nsIWidget* mFocusedWidget;
858     // mozilla::WritingMode value at the end (focus) of the selection
859     mozilla::WritingMode mWritingMode;
860     // Used by eQuerySelectionAsTransferable
861     nsCOMPtr<nsITransferable> mTransferable;
862     // Used by eQueryTextContent with font ranges requested
863     AutoTArray<mozilla::FontRange, 1> mFontRanges;
864     // Used by eQueryTextRectArray
865     nsTArray<mozilla::LayoutDeviceIntRect> mRectArray;
866     // true if selection is reversed (end < start)
867     bool mReversed;
868     // true if the selection exists
869     bool mHasSelection;
870     // true if DOM element under mouse belongs to widget
871     bool mWidgetIsHit;
872 
Replyfinal873     Reply()
874       : mContentsRoot(nullptr)
875       , mOffset(NOT_FOUND)
876       , mTentativeCaretOffset(NOT_FOUND)
877       , mFocusedWidget(nullptr)
878       , mReversed(false)
879       , mHasSelection(false)
880       , mWidgetIsHit(false)
881     {
882     }
883   } mReply;
884 
885   enum
886   {
887     NOT_FOUND = UINT32_MAX
888   };
889 
890   // values of mComputedScrollAction
891   enum
892   {
893     SCROLL_ACTION_NONE,
894     SCROLL_ACTION_LINE,
895     SCROLL_ACTION_PAGE
896   };
897 };
898 
899 /******************************************************************************
900  * mozilla::WidgetSelectionEvent
901  ******************************************************************************/
902 
903 class WidgetSelectionEvent : public WidgetGUIEvent
904 {
905 private:
906   friend class mozilla::dom::PBrowserParent;
907   friend class mozilla::dom::PBrowserChild;
908 
WidgetSelectionEvent()909   WidgetSelectionEvent()
910     : mOffset(0)
911     , mLength(0)
912     , mReversed(false)
913     , mExpandToClusterBoundary(true)
914     , mSucceeded(false)
915     , mUseNativeLineBreak(true)
916   {
917   }
918 
919 public:
AsSelectionEvent()920   virtual WidgetSelectionEvent* AsSelectionEvent() override
921   {
922     return this;
923   }
924 
WidgetSelectionEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget)925   WidgetSelectionEvent(bool aIsTrusted, EventMessage aMessage,
926                        nsIWidget* aWidget)
927     : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eSelectionEventClass)
928     , mOffset(0)
929     , mLength(0)
930     , mReversed(false)
931     , mExpandToClusterBoundary(true)
932     , mSucceeded(false)
933     , mUseNativeLineBreak(true)
934     , mReason(nsISelectionListener::NO_REASON)
935   {
936   }
937 
Duplicate()938   virtual WidgetEvent* Duplicate() const override
939   {
940     // This event isn't an internal event of any DOM event.
941     NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
942       "WidgetSelectionEvent needs to support Duplicate()");
943     MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()");
944     return nullptr;
945   }
946 
947   // Start offset of selection
948   uint32_t mOffset;
949   // Length of selection
950   uint32_t mLength;
951   // Selection "anchor" should be in front
952   bool mReversed;
953   // Cluster-based or character-based
954   bool mExpandToClusterBoundary;
955   // true if setting selection succeeded.
956   bool mSucceeded;
957   // true if native line breaks are used for mOffset and mLength
958   bool mUseNativeLineBreak;
959   // Fennec provides eSetSelection reason codes for downstream
960   // use in AccessibleCaret visibility logic.
961   int16_t mReason;
962 };
963 
964 /******************************************************************************
965  * mozilla::InternalEditorInputEvent
966  ******************************************************************************/
967 
968 class InternalEditorInputEvent : public InternalUIEvent
969 {
970 private:
InternalEditorInputEvent()971   InternalEditorInputEvent()
972     : mIsComposing(false)
973   {
974   }
975 
976 public:
AsEditorInputEvent()977   virtual InternalEditorInputEvent* AsEditorInputEvent() override
978   {
979     return this;
980   }
981 
InternalEditorInputEvent(bool aIsTrusted,EventMessage aMessage,nsIWidget * aWidget)982   InternalEditorInputEvent(bool aIsTrusted, EventMessage aMessage,
983                            nsIWidget* aWidget)
984     : InternalUIEvent(aIsTrusted, aMessage, aWidget, eEditorInputEventClass)
985     , mIsComposing(false)
986   {
987   }
988 
Duplicate()989   virtual WidgetEvent* Duplicate() const override
990   {
991     MOZ_ASSERT(mClass == eEditorInputEventClass,
992                "Duplicate() must be overridden by sub class");
993     // Not copying widget, it is a weak reference.
994     InternalEditorInputEvent* result =
995       new InternalEditorInputEvent(false, mMessage, nullptr);
996     result->AssignEditorInputEventData(*this, true);
997     result->mFlags = mFlags;
998     return result;
999   }
1000 
1001   bool mIsComposing;
1002 
AssignEditorInputEventData(const InternalEditorInputEvent & aEvent,bool aCopyTargets)1003   void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent,
1004                                   bool aCopyTargets)
1005   {
1006     AssignUIEventData(aEvent, aCopyTargets);
1007 
1008     mIsComposing = aEvent.mIsComposing;
1009   }
1010 };
1011 
1012 } // namespace mozilla
1013 
1014 #endif // mozilla_TextEvents_h__
1015