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