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