1 /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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_widget_IMEData_h_ 7 #define mozilla_widget_IMEData_h_ 8 9 #include "nsPoint.h" 10 #include "nsRect.h" 11 #include "nsStringGlue.h" 12 13 class nsIWidget; 14 15 namespace mozilla { 16 17 class WritingMode; 18 19 } // namespace mozilla 20 21 /** 22 * Preference for receiving IME updates 23 * 24 * If mWantUpdates is not NOTIFY_NOTHING, nsTextStateManager will observe text 25 * change and/or selection change and call nsIWidget::NotifyIME() with 26 * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE. 27 * Please note that the text change observing cost is very expensive especially 28 * on an HTML editor has focus. 29 * If the IME implementation on a particular platform doesn't care about 30 * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE, 31 * they should set mWantUpdates to NOTIFY_NOTHING to avoid the cost. 32 * If the IME implementation needs notifications even while our process is 33 * deactive, it should also set NOTIFY_DURING_DEACTIVE. 34 */ 35 struct nsIMEUpdatePreference final 36 { 37 typedef uint8_t Notifications; 38 39 enum : Notifications 40 { 41 NOTIFY_NOTHING = 0, 42 NOTIFY_TEXT_CHANGE = 1 << 1, 43 NOTIFY_POSITION_CHANGE = 1 << 2, 44 // NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR is used when mouse button is pressed 45 // or released on a character in the focused editor. The notification is 46 // notified to IME as a mouse event. If it's consumed by IME, NotifyIME() 47 // returns NS_SUCCESS_EVENT_CONSUMED. Otherwise, it returns NS_OK if it's 48 // handled without any error. 49 NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR = 1 << 3, 50 // NOTE: NOTIFY_DURING_DEACTIVE isn't supported in environments where two 51 // or more compositions are possible. E.g., Mac and Linux (GTK). 52 NOTIFY_DURING_DEACTIVE = 1 << 7 53 }; 54 nsIMEUpdatePreferencefinal55 nsIMEUpdatePreference() 56 : mWantUpdates(NOTIFY_NOTHING) 57 { 58 } 59 nsIMEUpdatePreferencefinal60 explicit nsIMEUpdatePreference(Notifications aWantUpdates) 61 : mWantUpdates(aWantUpdates) 62 { 63 } 64 65 nsIMEUpdatePreference operator|(const nsIMEUpdatePreference& aOther) const 66 { 67 return nsIMEUpdatePreference(aOther.mWantUpdates | mWantUpdates); 68 } 69 WantTextChangefinal70 bool WantTextChange() const 71 { 72 return !!(mWantUpdates & NOTIFY_TEXT_CHANGE); 73 } 74 WantPositionChangedfinal75 bool WantPositionChanged() const 76 { 77 return !!(mWantUpdates & NOTIFY_POSITION_CHANGE); 78 } 79 WantChangesfinal80 bool WantChanges() const 81 { 82 return WantTextChange(); 83 } 84 WantMouseButtonEventOnCharfinal85 bool WantMouseButtonEventOnChar() const 86 { 87 return !!(mWantUpdates & NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR); 88 } 89 WantDuringDeactivefinal90 bool WantDuringDeactive() const 91 { 92 return !!(mWantUpdates & NOTIFY_DURING_DEACTIVE); 93 } 94 95 Notifications mWantUpdates; 96 }; 97 98 /** 99 * Contains IMEStatus plus information about the current 100 * input context that the IME can use as hints if desired. 101 */ 102 103 namespace mozilla { 104 namespace widget { 105 106 struct IMEState final 107 { 108 /** 109 * IME enabled states, the mEnabled value of 110 * SetInputContext()/GetInputContext() should be one value of following 111 * values. 112 * 113 * WARNING: If you change these values, you also need to edit: 114 * nsIDOMWindowUtils.idl 115 * nsContentUtils::GetWidgetStatusFromIMEStatus 116 */ 117 enum Enabled 118 { 119 /** 120 * 'Disabled' means the user cannot use IME. So, the IME open state should 121 * be 'closed' during 'disabled'. 122 */ 123 DISABLED, 124 /** 125 * 'Enabled' means the user can use IME. 126 */ 127 ENABLED, 128 /** 129 * 'Password' state is a special case for the password editors. 130 * E.g., on mac, the password editors should disable the non-Roman 131 * keyboard layouts at getting focus. Thus, the password editor may have 132 * special rules on some platforms. 133 */ 134 PASSWORD, 135 /** 136 * This state is used when a plugin is focused. 137 * When a plug-in is focused content, we should send native events 138 * directly. Because we don't process some native events, but they may 139 * be needed by the plug-in. 140 */ 141 PLUGIN, 142 /** 143 * 'Unknown' is useful when you cache this enum. So, this shouldn't be 144 * used with nsIWidget::SetInputContext(). 145 */ 146 UNKNOWN 147 }; 148 Enabled mEnabled; 149 150 /** 151 * IME open states the mOpen value of SetInputContext() should be one value of 152 * OPEN, CLOSE or DONT_CHANGE_OPEN_STATE. GetInputContext() should return 153 * OPEN, CLOSE or OPEN_STATE_NOT_SUPPORTED. 154 */ 155 enum Open 156 { 157 /** 158 * 'Unsupported' means the platform cannot return actual IME open state. 159 * This value is used only by GetInputContext(). 160 */ 161 OPEN_STATE_NOT_SUPPORTED, 162 /** 163 * 'Don't change' means the widget shouldn't change IME open state when 164 * SetInputContext() is called. 165 */ 166 DONT_CHANGE_OPEN_STATE = OPEN_STATE_NOT_SUPPORTED, 167 /** 168 * 'Open' means that IME should compose in its primary language (or latest 169 * input mode except direct ASCII character input mode). Even if IME is 170 * opened by this value, users should be able to close IME by theirselves. 171 * Web contents can specify this value by |ime-mode: active;|. 172 */ 173 OPEN, 174 /** 175 * 'Closed' means that IME shouldn't handle key events (or should handle 176 * as ASCII character inputs on mobile device). Even if IME is closed by 177 * this value, users should be able to open IME by theirselves. 178 * Web contents can specify this value by |ime-mode: inactive;|. 179 */ 180 CLOSED 181 }; 182 Open mOpen; 183 IMEStatefinal184 IMEState() 185 : mEnabled(ENABLED) 186 , mOpen(DONT_CHANGE_OPEN_STATE) 187 { 188 } 189 190 explicit IMEState(Enabled aEnabled, Open aOpen = DONT_CHANGE_OPEN_STATE) mEnabledfinal191 : mEnabled(aEnabled) 192 , mOpen(aOpen) 193 { 194 } 195 196 // Returns true if the user can input characters. 197 // This means that a plain text editor, an HTML editor, a password editor or 198 // a plain text editor whose ime-mode is "disabled". IsEditablefinal199 bool IsEditable() const 200 { 201 return mEnabled == ENABLED || mEnabled == PASSWORD; 202 } 203 // Returns true if the user might be able to input characters. 204 // This means that a plain text editor, an HTML editor, a password editor, 205 // a plain text editor whose ime-mode is "disabled" or a windowless plugin 206 // has focus. MaybeEditablefinal207 bool MaybeEditable() const 208 { 209 return IsEditable() || mEnabled == PLUGIN; 210 } 211 }; 212 213 // NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context. 214 // If there can be only one IME composition in a process, this can be used. 215 #define NS_ONLY_ONE_NATIVE_IME_CONTEXT \ 216 (reinterpret_cast<void*>(static_cast<intptr_t>(-1))) 217 218 struct NativeIMEContext final 219 { 220 // Pointer to native IME context. Typically this is the result of 221 // nsIWidget::GetNativeData(NS_RAW_NATIVE_IME_CONTEXT) in the parent process. 222 // See also NS_ONLY_ONE_NATIVE_IME_CONTEXT. 223 uintptr_t mRawNativeIMEContext; 224 // Process ID of the origin of mNativeIMEContext. 225 uint64_t mOriginProcessID; 226 NativeIMEContextfinal227 NativeIMEContext() 228 { 229 Init(nullptr); 230 } 231 NativeIMEContextfinal232 explicit NativeIMEContext(nsIWidget* aWidget) 233 { 234 Init(aWidget); 235 } 236 IsValidfinal237 bool IsValid() const 238 { 239 return mRawNativeIMEContext && 240 mOriginProcessID != static_cast<uintptr_t>(-1); 241 } 242 243 void Init(nsIWidget* aWidget); InitWithRawNativeIMEContextfinal244 void InitWithRawNativeIMEContext(const void* aRawNativeIMEContext) 245 { 246 InitWithRawNativeIMEContext(const_cast<void*>(aRawNativeIMEContext)); 247 } 248 void InitWithRawNativeIMEContext(void* aRawNativeIMEContext); 249 250 bool operator==(const NativeIMEContext& aOther) const 251 { 252 return mRawNativeIMEContext == aOther.mRawNativeIMEContext && 253 mOriginProcessID == aOther.mOriginProcessID; 254 } 255 bool operator!=(const NativeIMEContext& aOther) const 256 { 257 return !(*this == aOther); 258 } 259 }; 260 261 struct InputContext final 262 { InputContextfinal263 InputContext() 264 : mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT) 265 , mMayBeIMEUnaware(false) 266 { 267 } 268 IsPasswordEditorfinal269 bool IsPasswordEditor() const 270 { 271 return mHTMLInputType.LowerCaseEqualsLiteral("password"); 272 } 273 274 IMEState mIMEState; 275 276 /* The type of the input if the input is a html input field */ 277 nsString mHTMLInputType; 278 279 /* The type of the inputmode */ 280 nsString mHTMLInputInputmode; 281 282 /* A hint for the action that is performed when the input is submitted */ 283 nsString mActionHint; 284 285 /** 286 * mOrigin indicates whether this focus event refers to main or remote 287 * content. 288 */ 289 enum Origin 290 { 291 // Adjusting focus of content on the main process 292 ORIGIN_MAIN, 293 // Adjusting focus of content in a remote process 294 ORIGIN_CONTENT 295 }; 296 Origin mOrigin; 297 298 /* True if the webapp may be unaware of IME events such as input event or 299 * composiion events. This enables a key-events-only mode on Android for 300 * compatibility with webapps relying on key listeners. */ 301 bool mMayBeIMEUnaware; 302 IsOriginMainProcessfinal303 bool IsOriginMainProcess() const 304 { 305 return mOrigin == ORIGIN_MAIN; 306 } 307 IsOriginContentProcessfinal308 bool IsOriginContentProcess() const 309 { 310 return mOrigin == ORIGIN_CONTENT; 311 } 312 IsOriginCurrentProcessfinal313 bool IsOriginCurrentProcess() const 314 { 315 if (XRE_IsParentProcess()) { 316 return IsOriginMainProcess(); 317 } 318 return IsOriginContentProcess(); 319 } 320 }; 321 322 struct InputContextAction final 323 { 324 /** 325 * mCause indicates what action causes calling nsIWidget::SetInputContext(). 326 * It must be one of following values. 327 */ 328 enum Cause 329 { 330 // The cause is unknown but originated from content. Focus might have been 331 // changed by content script. 332 CAUSE_UNKNOWN, 333 // The cause is unknown but originated from chrome. Focus might have been 334 // changed by chrome script. 335 CAUSE_UNKNOWN_CHROME, 336 // The cause is user's keyboard operation. 337 CAUSE_KEY, 338 // The cause is user's mouse operation. 339 CAUSE_MOUSE, 340 // The cause is user's touch operation (implies mouse) 341 CAUSE_TOUCH 342 }; 343 Cause mCause; 344 345 /** 346 * mFocusChange indicates what happened for focus. 347 */ 348 enum FocusChange 349 { 350 FOCUS_NOT_CHANGED, 351 // A content got focus. 352 GOT_FOCUS, 353 // Focused content lost focus. 354 LOST_FOCUS, 355 // Menu got pseudo focus that means focused content isn't changed but 356 // keyboard events will be handled by menu. 357 MENU_GOT_PSEUDO_FOCUS, 358 // Menu lost pseudo focus that means focused content will handle keyboard 359 // events. 360 MENU_LOST_PSEUDO_FOCUS 361 }; 362 FocusChange mFocusChange; 363 ContentGotFocusByTrustedCausefinal364 bool ContentGotFocusByTrustedCause() const 365 { 366 return (mFocusChange == GOT_FOCUS && 367 mCause != CAUSE_UNKNOWN); 368 } 369 UserMightRequestOpenVKBfinal370 bool UserMightRequestOpenVKB() const 371 { 372 return (mFocusChange == FOCUS_NOT_CHANGED && 373 (mCause == CAUSE_MOUSE || mCause == CAUSE_TOUCH)); 374 } 375 IsUserActionfinal376 static bool IsUserAction(Cause aCause) 377 { 378 switch (aCause) { 379 case CAUSE_KEY: 380 case CAUSE_MOUSE: 381 case CAUSE_TOUCH: 382 return true; 383 default: 384 return false; 385 } 386 } 387 InputContextActionfinal388 InputContextAction() 389 : mCause(CAUSE_UNKNOWN) 390 , mFocusChange(FOCUS_NOT_CHANGED) 391 { 392 } 393 394 explicit InputContextAction(Cause aCause, 395 FocusChange aFocusChange = FOCUS_NOT_CHANGED) mCausefinal396 : mCause(aCause) 397 , mFocusChange(aFocusChange) 398 { 399 } 400 }; 401 402 // IMEMessage is shared by IMEStateManager and TextComposition. 403 // Update values in GeckoEditable.java if you make changes here. 404 // XXX Negative values are used in Android... 405 typedef int8_t IMEMessageType; 406 enum IMEMessage : IMEMessageType 407 { 408 // This is used by IMENotification internally. This means that the instance 409 // hasn't been initialized yet. 410 NOTIFY_IME_OF_NOTHING, 411 // An editable content is getting focus 412 NOTIFY_IME_OF_FOCUS, 413 // An editable content is losing focus 414 NOTIFY_IME_OF_BLUR, 415 // Selection in the focused editable content is changed 416 NOTIFY_IME_OF_SELECTION_CHANGE, 417 // Text in the focused editable content is changed 418 NOTIFY_IME_OF_TEXT_CHANGE, 419 // Notified when a dispatched composition event is handled by the 420 // contents. This must be notified after the other notifications. 421 // Note that if a remote process has focus, this is notified only once when 422 // all dispatched events are handled completely. So, the receiver shouldn't 423 // count number of received this notification for comparing with the number 424 // of dispatched events. 425 // NOTE: If a composition event causes moving focus from the focused editor, 426 // this notification may not be notified as usual. Even in such case, 427 // NOTIFY_IME_OF_BLUR is always sent. So, notification listeners 428 // should tread the blur notification as including this if there is 429 // pending composition events. 430 NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, 431 // Position or size of focused element may be changed. 432 NOTIFY_IME_OF_POSITION_CHANGE, 433 // Mouse button event is fired on a character in focused editor 434 NOTIFY_IME_OF_MOUSE_BUTTON_EVENT, 435 // Request to commit current composition to IME 436 // (some platforms may not support) 437 REQUEST_TO_COMMIT_COMPOSITION, 438 // Request to cancel current composition to IME 439 // (some platforms may not support) 440 REQUEST_TO_CANCEL_COMPOSITION 441 }; 442 443 // FYI: Implemented in nsBaseWidget.cpp 444 const char* ToChar(IMEMessage aIMEMessage); 445 446 struct IMENotification final 447 { IMENotificationfinal448 IMENotification() 449 : mMessage(NOTIFY_IME_OF_NOTHING) 450 { 451 } 452 IMENotificationfinal453 IMENotification(const IMENotification& aOther) 454 : mMessage(NOTIFY_IME_OF_NOTHING) 455 { 456 Assign(aOther); 457 } 458 ~IMENotificationfinal459 ~IMENotification() 460 { 461 Clear(); 462 } 463 IMENotificationfinal464 MOZ_IMPLICIT IMENotification(IMEMessage aMessage) 465 : mMessage(aMessage) 466 { 467 switch (aMessage) { 468 case NOTIFY_IME_OF_SELECTION_CHANGE: 469 mSelectionChangeData.mString = new nsString(); 470 mSelectionChangeData.Clear(); 471 break; 472 case NOTIFY_IME_OF_TEXT_CHANGE: 473 mTextChangeData.Clear(); 474 break; 475 case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT: 476 mMouseButtonEventData.mEventMessage = eVoidEvent; 477 mMouseButtonEventData.mOffset = UINT32_MAX; 478 mMouseButtonEventData.mCursorPos.Set(nsIntPoint(0, 0)); 479 mMouseButtonEventData.mCharRect.Set(nsIntRect(0, 0, 0, 0)); 480 mMouseButtonEventData.mButton = -1; 481 mMouseButtonEventData.mButtons = 0; 482 mMouseButtonEventData.mModifiers = 0; 483 break; 484 default: 485 break; 486 } 487 } 488 Assignfinal489 void Assign(const IMENotification& aOther) 490 { 491 bool changingMessage = mMessage != aOther.mMessage; 492 if (changingMessage) { 493 Clear(); 494 mMessage = aOther.mMessage; 495 } 496 switch (mMessage) { 497 case NOTIFY_IME_OF_SELECTION_CHANGE: 498 if (changingMessage) { 499 mSelectionChangeData.mString = new nsString(); 500 } 501 mSelectionChangeData.Assign(aOther.mSelectionChangeData); 502 break; 503 case NOTIFY_IME_OF_TEXT_CHANGE: 504 mTextChangeData = aOther.mTextChangeData; 505 break; 506 case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT: 507 mMouseButtonEventData = aOther.mMouseButtonEventData; 508 break; 509 default: 510 break; 511 } 512 } 513 514 IMENotification& operator=(const IMENotification& aOther) 515 { 516 Assign(aOther); 517 return *this; 518 } 519 Clearfinal520 void Clear() 521 { 522 if (mMessage == NOTIFY_IME_OF_SELECTION_CHANGE) { 523 MOZ_ASSERT(mSelectionChangeData.mString); 524 delete mSelectionChangeData.mString; 525 mSelectionChangeData.mString = nullptr; 526 } 527 mMessage = NOTIFY_IME_OF_NOTHING; 528 } 529 HasNotificationfinal530 bool HasNotification() const 531 { 532 return mMessage != NOTIFY_IME_OF_NOTHING; 533 } 534 MergeWithfinal535 void MergeWith(const IMENotification& aNotification) 536 { 537 switch (mMessage) { 538 case NOTIFY_IME_OF_NOTHING: 539 MOZ_ASSERT(aNotification.mMessage != NOTIFY_IME_OF_NOTHING); 540 Assign(aNotification); 541 break; 542 case NOTIFY_IME_OF_SELECTION_CHANGE: 543 MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE); 544 mSelectionChangeData.Assign(aNotification.mSelectionChangeData); 545 break; 546 case NOTIFY_IME_OF_TEXT_CHANGE: 547 MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE); 548 mTextChangeData += aNotification.mTextChangeData; 549 break; 550 case NOTIFY_IME_OF_POSITION_CHANGE: 551 case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: 552 MOZ_ASSERT(aNotification.mMessage == mMessage); 553 break; 554 default: 555 MOZ_CRASH("Merging notification isn't supported"); 556 break; 557 } 558 } 559 560 IMEMessage mMessage; 561 562 struct Point 563 { 564 int32_t mX; 565 int32_t mY; 566 Setfinal::Point567 void Set(const nsIntPoint& aPoint) 568 { 569 mX = aPoint.x; 570 mY = aPoint.y; 571 } AsIntPointfinal::Point572 nsIntPoint AsIntPoint() const 573 { 574 return nsIntPoint(mX, mY); 575 } 576 }; 577 578 struct Rect 579 { 580 int32_t mX; 581 int32_t mY; 582 int32_t mWidth; 583 int32_t mHeight; 584 Setfinal::Rect585 void Set(const nsIntRect& aRect) 586 { 587 mX = aRect.x; 588 mY = aRect.y; 589 mWidth = aRect.width; 590 mHeight = aRect.height; 591 } AsIntRectfinal::Rect592 nsIntRect AsIntRect() const 593 { 594 return nsIntRect(mX, mY, mWidth, mHeight); 595 } 596 }; 597 598 // NOTIFY_IME_OF_SELECTION_CHANGE specific data 599 struct SelectionChangeDataBase 600 { 601 // Selection range. 602 uint32_t mOffset; 603 604 // Selected string 605 nsString* mString; 606 607 // Writing mode at the selection. 608 uint8_t mWritingMode; 609 610 bool mReversed; 611 bool mCausedByComposition; 612 bool mCausedBySelectionEvent; 613 bool mOccurredDuringComposition; 614 615 void SetWritingMode(const WritingMode& aWritingMode); 616 WritingMode GetWritingMode() const; 617 StartOffsetfinal::SelectionChangeDataBase618 uint32_t StartOffset() const 619 { 620 return mOffset + (mReversed ? Length() : 0); 621 } EndOffsetfinal::SelectionChangeDataBase622 uint32_t EndOffset() const 623 { 624 return mOffset + (mReversed ? 0 : Length()); 625 } Stringfinal::SelectionChangeDataBase626 const nsString& String() const 627 { 628 return *mString; 629 } Lengthfinal::SelectionChangeDataBase630 uint32_t Length() const 631 { 632 return mString->Length(); 633 } IsInInt32Rangefinal::SelectionChangeDataBase634 bool IsInInt32Range() const 635 { 636 return mOffset + Length() <= INT32_MAX; 637 } IsCollapsedfinal::SelectionChangeDataBase638 bool IsCollapsed() const 639 { 640 return mString->IsEmpty(); 641 } ClearSelectionDatafinal::SelectionChangeDataBase642 void ClearSelectionData() 643 { 644 mOffset = UINT32_MAX; 645 mString->Truncate(); 646 mWritingMode = 0; 647 mReversed = false; 648 } Clearfinal::SelectionChangeDataBase649 void Clear() 650 { 651 ClearSelectionData(); 652 mCausedByComposition = false; 653 mCausedBySelectionEvent = false; 654 mOccurredDuringComposition = false; 655 } IsValidfinal::SelectionChangeDataBase656 bool IsValid() const 657 { 658 return mOffset != UINT32_MAX; 659 } Assignfinal::SelectionChangeDataBase660 void Assign(const SelectionChangeDataBase& aOther) 661 { 662 mOffset = aOther.mOffset; 663 *mString = aOther.String(); 664 mWritingMode = aOther.mWritingMode; 665 mReversed = aOther.mReversed; 666 AssignReason(aOther.mCausedByComposition, 667 aOther.mCausedBySelectionEvent, 668 aOther.mOccurredDuringComposition); 669 } AssignReasonfinal::SelectionChangeDataBase670 void AssignReason(bool aCausedByComposition, 671 bool aCausedBySelectionEvent, 672 bool aOccurredDuringComposition) 673 { 674 mCausedByComposition = aCausedByComposition; 675 mCausedBySelectionEvent = aCausedBySelectionEvent; 676 mOccurredDuringComposition = aOccurredDuringComposition; 677 } 678 }; 679 680 // SelectionChangeDataBase cannot have constructors because it's used in 681 // the union. Therefore, SelectionChangeData should only implement 682 // constructors. In other words, add other members to 683 // SelectionChangeDataBase. 684 struct SelectionChangeData final : public SelectionChangeDataBase 685 { SelectionChangeDatafinal::final686 SelectionChangeData() 687 { 688 mString = &mStringInstance; 689 Clear(); 690 } SelectionChangeDatafinal::final691 explicit SelectionChangeData(const SelectionChangeDataBase& aOther) 692 { 693 mString = &mStringInstance; 694 Assign(aOther); 695 } SelectionChangeDatafinal::final696 SelectionChangeData(const SelectionChangeData& aOther) 697 { 698 mString = &mStringInstance; 699 Assign(aOther); 700 } 701 SelectionChangeData& operator=(const SelectionChangeDataBase& aOther) 702 { 703 mString = &mStringInstance; 704 Assign(aOther); 705 return *this; 706 } 707 SelectionChangeData& operator=(const SelectionChangeData& aOther) 708 { 709 mString = &mStringInstance; 710 Assign(aOther); 711 return *this; 712 } 713 714 private: 715 // When SelectionChangeData is used outside of union, it shouldn't create 716 // nsString instance in the heap as far as possible. 717 nsString mStringInstance; 718 }; 719 720 struct TextChangeDataBase 721 { 722 // mStartOffset is the start offset of modified or removed text in 723 // original content and inserted text in new content. 724 uint32_t mStartOffset; 725 // mRemovalEndOffset is the end offset of modified or removed text in 726 // original content. If the value is same as mStartOffset, no text hasn't 727 // been removed yet. 728 uint32_t mRemovedEndOffset; 729 // mAddedEndOffset is the end offset of inserted text or same as 730 // mStartOffset if just removed. The vlaue is offset in the new content. 731 uint32_t mAddedEndOffset; 732 733 // Note that TextChangeDataBase may be the result of merging two or more 734 // changes especially in e10s mode. 735 736 // mCausedOnlyByComposition is true only when *all* merged changes are 737 // caused by composition. 738 bool mCausedOnlyByComposition; 739 // mIncludingChangesDuringComposition is true if at least one change which 740 // is not caused by composition occurred during the last composition. 741 // Note that if after the last composition is finished and there are some 742 // changes not caused by composition, this is set to false. 743 bool mIncludingChangesDuringComposition; 744 // mIncludingChangesWithoutComposition is true if there is at least one 745 // change which did occur when there wasn't a composition ongoing. 746 bool mIncludingChangesWithoutComposition; 747 OldLengthfinal::TextChangeDataBase748 uint32_t OldLength() const 749 { 750 MOZ_ASSERT(IsValid()); 751 return mRemovedEndOffset - mStartOffset; 752 } NewLengthfinal::TextChangeDataBase753 uint32_t NewLength() const 754 { 755 MOZ_ASSERT(IsValid()); 756 return mAddedEndOffset - mStartOffset; 757 } 758 759 // Positive if text is added. Negative if text is removed. Differencefinal::TextChangeDataBase760 int64_t Difference() const 761 { 762 return mAddedEndOffset - mRemovedEndOffset; 763 } 764 IsInInt32Rangefinal::TextChangeDataBase765 bool IsInInt32Range() const 766 { 767 MOZ_ASSERT(IsValid()); 768 return mStartOffset <= INT32_MAX && 769 mRemovedEndOffset <= INT32_MAX && 770 mAddedEndOffset <= INT32_MAX; 771 } 772 IsValidfinal::TextChangeDataBase773 bool IsValid() const 774 { 775 return !(mStartOffset == UINT32_MAX && 776 !mRemovedEndOffset && !mAddedEndOffset); 777 } 778 Clearfinal::TextChangeDataBase779 void Clear() 780 { 781 mStartOffset = UINT32_MAX; 782 mRemovedEndOffset = mAddedEndOffset = 0; 783 } 784 785 void MergeWith(const TextChangeDataBase& aOther); 786 TextChangeDataBase& operator+=(const TextChangeDataBase& aOther) 787 { 788 MergeWith(aOther); 789 return *this; 790 } 791 792 #ifdef DEBUG 793 void Test(); 794 #endif // #ifdef DEBUG 795 }; 796 797 // TextChangeDataBase cannot have constructors because they are used in union. 798 // Therefore, TextChangeData should only implement constructor. In other 799 // words, add other members to TextChangeDataBase. 800 struct TextChangeData : public TextChangeDataBase 801 { TextChangeDatafinal::TextChangeData802 TextChangeData() { Clear(); } 803 TextChangeDatafinal::TextChangeData804 TextChangeData(uint32_t aStartOffset, 805 uint32_t aRemovedEndOffset, 806 uint32_t aAddedEndOffset, 807 bool aCausedByComposition, 808 bool aOccurredDuringComposition) 809 { 810 MOZ_ASSERT(aRemovedEndOffset >= aStartOffset, 811 "removed end offset must not be smaller than start offset"); 812 MOZ_ASSERT(aAddedEndOffset >= aStartOffset, 813 "added end offset must not be smaller than start offset"); 814 mStartOffset = aStartOffset; 815 mRemovedEndOffset = aRemovedEndOffset; 816 mAddedEndOffset = aAddedEndOffset; 817 mCausedOnlyByComposition = aCausedByComposition; 818 mIncludingChangesDuringComposition = 819 !aCausedByComposition && aOccurredDuringComposition; 820 mIncludingChangesWithoutComposition = 821 !aCausedByComposition && !aOccurredDuringComposition; 822 } 823 }; 824 825 struct MouseButtonEventData 826 { 827 // The value of WidgetEvent::mMessage 828 EventMessage mEventMessage; 829 // Character offset from the start of the focused editor under the cursor 830 uint32_t mOffset; 831 // Cursor position in pixels relative to the widget 832 Point mCursorPos; 833 // Character rect in pixels under the cursor relative to the widget 834 Rect mCharRect; 835 // The value of WidgetMouseEventBase::button and buttons 836 int16_t mButton; 837 int16_t mButtons; 838 // The value of WidgetInputEvent::modifiers 839 Modifiers mModifiers; 840 }; 841 842 union 843 { 844 // NOTIFY_IME_OF_SELECTION_CHANGE specific data 845 SelectionChangeDataBase mSelectionChangeData; 846 847 // NOTIFY_IME_OF_TEXT_CHANGE specific data 848 TextChangeDataBase mTextChangeData; 849 850 // NOTIFY_IME_OF_MOUSE_BUTTON_EVENT specific data 851 MouseButtonEventData mMouseButtonEventData; 852 }; 853 SetDatafinal854 void SetData(const SelectionChangeDataBase& aSelectionChangeData) 855 { 856 MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_SELECTION_CHANGE); 857 mSelectionChangeData.Assign(aSelectionChangeData); 858 } 859 SetDatafinal860 void SetData(const TextChangeDataBase& aTextChangeData) 861 { 862 MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_TEXT_CHANGE); 863 mTextChangeData = aTextChangeData; 864 } 865 }; 866 867 struct CandidateWindowPosition 868 { 869 // Upper left corner of the candidate window if mExcludeRect is false. 870 // Otherwise, the position currently interested. E.g., caret position. 871 LayoutDeviceIntPoint mPoint; 872 // Rect which shouldn't be overlapped with the candidate window. 873 // This is valid only when mExcludeRect is true. 874 LayoutDeviceIntRect mRect; 875 // See explanation of mPoint and mRect. 876 bool mExcludeRect; 877 }; 878 879 } // namespace widget 880 } // namespace mozilla 881 882 #endif // #ifndef mozilla_widget_IMEData_h_ 883