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