Bug 1626988 [wpt PR 22658] - wake lock: Remove WakeLockPermissionDescriptor, use...
[gecko.git] / widget / IMEData.h
blob6bebecfb75b87f98b467de942f06282fb592a159
1 /* -*- Mode: C++; tab-width: 40; 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/. */
6 #ifndef mozilla_widget_IMEData_h_
7 #define mozilla_widget_IMEData_h_
9 #include "nsPoint.h"
10 #include "nsRect.h"
11 #include "nsString.h"
12 #include "nsXULAppAPI.h"
13 #include "Units.h"
15 class nsIWidget;
17 namespace mozilla {
19 class WritingMode;
21 namespace widget {
23 /**
24 * Preference for receiving IME updates
26 * If mWantUpdates is not NOTIFY_NOTHING, nsTextStateManager will observe text
27 * change and/or selection change and call nsIWidget::NotifyIME() with
28 * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE.
29 * Please note that the text change observing cost is very expensive especially
30 * on an HTML editor has focus.
31 * If the IME implementation on a particular platform doesn't care about
32 * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE,
33 * they should set mWantUpdates to NOTIFY_NOTHING to avoid the cost.
34 * If the IME implementation needs notifications even while our process is
35 * deactive, it should also set NOTIFY_DURING_DEACTIVE.
37 struct IMENotificationRequests final {
38 typedef uint8_t Notifications;
40 enum : Notifications {
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,
54 NOTIFY_ALL = NOTIFY_TEXT_CHANGE | NOTIFY_POSITION_CHANGE |
55 NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR,
58 IMENotificationRequests() : mWantUpdates(NOTIFY_NOTHING) {}
60 explicit IMENotificationRequests(Notifications aWantUpdates)
61 : mWantUpdates(aWantUpdates) {}
63 IMENotificationRequests operator|(
64 const IMENotificationRequests& aOther) const {
65 return IMENotificationRequests(aOther.mWantUpdates | mWantUpdates);
67 IMENotificationRequests& operator|=(const IMENotificationRequests& aOther) {
68 mWantUpdates |= aOther.mWantUpdates;
69 return *this;
71 bool operator==(const IMENotificationRequests& aOther) const {
72 return mWantUpdates == aOther.mWantUpdates;
75 bool WantTextChange() const { return !!(mWantUpdates & NOTIFY_TEXT_CHANGE); }
77 bool WantPositionChanged() const {
78 return !!(mWantUpdates & NOTIFY_POSITION_CHANGE);
81 bool WantChanges() const { return WantTextChange(); }
83 bool WantMouseButtonEventOnChar() const {
84 return !!(mWantUpdates & NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR);
87 bool WantDuringDeactive() const {
88 return !!(mWantUpdates & NOTIFY_DURING_DEACTIVE);
91 Notifications mWantUpdates;
94 /**
95 * Contains IMEStatus plus information about the current
96 * input context that the IME can use as hints if desired.
99 struct IMEState final {
101 * IME enabled states, the mEnabled value of
102 * SetInputContext()/GetInputContext() should be one value of following
103 * values.
105 * WARNING: If you change these values, you also need to edit:
106 * nsIDOMWindowUtils.idl
107 * nsContentUtils::GetWidgetStatusFromIMEStatus
109 enum Enabled {
111 * 'Disabled' means the user cannot use IME. So, the IME open state should
112 * be 'closed' during 'disabled'.
114 DISABLED,
116 * 'Enabled' means the user can use IME.
118 ENABLED,
120 * 'Password' state is a special case for the password editors.
121 * E.g., on mac, the password editors should disable the non-Roman
122 * keyboard layouts at getting focus. Thus, the password editor may have
123 * special rules on some platforms.
125 PASSWORD,
127 * This state is used when a plugin is focused.
128 * When a plug-in is focused content, we should send native events
129 * directly. Because we don't process some native events, but they may
130 * be needed by the plug-in.
132 PLUGIN,
134 * 'Unknown' is useful when you cache this enum. So, this shouldn't be
135 * used with nsIWidget::SetInputContext().
137 UNKNOWN
139 Enabled mEnabled;
142 * IME open states the mOpen value of SetInputContext() should be one value of
143 * OPEN, CLOSE or DONT_CHANGE_OPEN_STATE. GetInputContext() should return
144 * OPEN, CLOSE or OPEN_STATE_NOT_SUPPORTED.
146 enum Open {
148 * 'Unsupported' means the platform cannot return actual IME open state.
149 * This value is used only by GetInputContext().
151 OPEN_STATE_NOT_SUPPORTED,
153 * 'Don't change' means the widget shouldn't change IME open state when
154 * SetInputContext() is called.
156 DONT_CHANGE_OPEN_STATE = OPEN_STATE_NOT_SUPPORTED,
158 * 'Open' means that IME should compose in its primary language (or latest
159 * input mode except direct ASCII character input mode). Even if IME is
160 * opened by this value, users should be able to close IME by theirselves.
161 * Web contents can specify this value by |ime-mode: active;|.
163 OPEN,
165 * 'Closed' means that IME shouldn't handle key events (or should handle
166 * as ASCII character inputs on mobile device). Even if IME is closed by
167 * this value, users should be able to open IME by theirselves.
168 * Web contents can specify this value by |ime-mode: inactive;|.
170 CLOSED
172 Open mOpen;
174 IMEState() : mEnabled(ENABLED), mOpen(DONT_CHANGE_OPEN_STATE) {}
176 explicit IMEState(Enabled aEnabled, Open aOpen = DONT_CHANGE_OPEN_STATE)
177 : mEnabled(aEnabled), mOpen(aOpen) {}
179 // Returns true if the user can input characters.
180 // This means that a plain text editor, an HTML editor, a password editor or
181 // a plain text editor whose ime-mode is "disabled".
182 bool IsEditable() const {
183 return mEnabled == ENABLED || mEnabled == PASSWORD;
185 // Returns true if the user might be able to input characters.
186 // This means that a plain text editor, an HTML editor, a password editor,
187 // a plain text editor whose ime-mode is "disabled" or a windowless plugin
188 // has focus.
189 bool MaybeEditable() const { return IsEditable() || mEnabled == PLUGIN; }
192 // NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context.
193 // If there can be only one IME composition in a process, this can be used.
194 #define NS_ONLY_ONE_NATIVE_IME_CONTEXT \
195 (reinterpret_cast<void*>(static_cast<intptr_t>(-1)))
197 struct NativeIMEContext final {
198 // Pointer to native IME context. Typically this is the result of
199 // nsIWidget::GetNativeData(NS_RAW_NATIVE_IME_CONTEXT) in the parent process.
200 // See also NS_ONLY_ONE_NATIVE_IME_CONTEXT.
201 uintptr_t mRawNativeIMEContext;
202 // Process ID of the origin of mNativeIMEContext.
203 uint64_t mOriginProcessID;
205 NativeIMEContext() : mRawNativeIMEContext(0), mOriginProcessID(0) {
206 Init(nullptr);
209 explicit NativeIMEContext(nsIWidget* aWidget)
210 : mRawNativeIMEContext(0), mOriginProcessID(0) {
211 Init(aWidget);
214 bool IsValid() const {
215 return mRawNativeIMEContext &&
216 mOriginProcessID != static_cast<uintptr_t>(-1);
219 void Init(nsIWidget* aWidget);
220 void InitWithRawNativeIMEContext(const void* aRawNativeIMEContext) {
221 InitWithRawNativeIMEContext(const_cast<void*>(aRawNativeIMEContext));
223 void InitWithRawNativeIMEContext(void* aRawNativeIMEContext);
225 bool operator==(const NativeIMEContext& aOther) const {
226 return mRawNativeIMEContext == aOther.mRawNativeIMEContext &&
227 mOriginProcessID == aOther.mOriginProcessID;
229 bool operator!=(const NativeIMEContext& aOther) const {
230 return !(*this == aOther);
234 struct InputContext final {
235 InputContext()
236 : mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT),
237 mMayBeIMEUnaware(false),
238 mHasHandledUserInput(false),
239 mInPrivateBrowsing(false) {}
241 // If InputContext instance is a static variable, any heap allocated stuff
242 // of its members need to be deleted at XPCOM shutdown. Otherwise, it's
243 // detected as memory leak.
244 void ShutDown() {
245 mHTMLInputType.Truncate();
246 mHTMLInputInputmode.Truncate();
247 mActionHint.Truncate();
250 bool IsPasswordEditor() const {
251 return mHTMLInputType.LowerCaseEqualsLiteral("password");
254 IMEState mIMEState;
256 /* The type of the input if the input is a html input field */
257 nsString mHTMLInputType;
259 /* The type of the inputmode */
260 nsString mHTMLInputInputmode;
262 /* A hint for the action that is performed when the input is submitted */
263 nsString mActionHint;
266 * mOrigin indicates whether this focus event refers to main or remote
267 * content.
269 enum Origin {
270 // Adjusting focus of content on the main process
271 ORIGIN_MAIN,
272 // Adjusting focus of content in a remote process
273 ORIGIN_CONTENT
275 Origin mOrigin;
277 /* True if the webapp may be unaware of IME events such as input event or
278 * composiion events. This enables a key-events-only mode on Android for
279 * compatibility with webapps relying on key listeners. */
280 bool mMayBeIMEUnaware;
283 * True if the document has ever received user input
285 bool mHasHandledUserInput;
287 /* Whether the owning document of the input element has been loaded
288 * in private browsing mode. */
289 bool mInPrivateBrowsing;
291 bool IsOriginMainProcess() const { return mOrigin == ORIGIN_MAIN; }
293 bool IsOriginContentProcess() const { return mOrigin == ORIGIN_CONTENT; }
295 bool IsOriginCurrentProcess() const {
296 if (XRE_IsParentProcess()) {
297 return IsOriginMainProcess();
299 return IsOriginContentProcess();
303 // FYI: Implemented in nsBaseWidget.cpp
304 const char* ToChar(InputContext::Origin aOrigin);
306 struct InputContextAction final {
308 * mCause indicates what action causes calling nsIWidget::SetInputContext().
309 * It must be one of following values.
311 enum Cause {
312 // The cause is unknown but originated from content. Focus might have been
313 // changed by content script.
314 CAUSE_UNKNOWN,
315 // The cause is unknown but originated from chrome. Focus might have been
316 // changed by chrome script.
317 CAUSE_UNKNOWN_CHROME,
318 // The cause is user's keyboard operation.
319 CAUSE_KEY,
320 // The cause is user's mouse operation.
321 CAUSE_MOUSE,
322 // The cause is user's touch operation (implies mouse)
323 CAUSE_TOUCH,
324 // The cause is users' long press operation.
325 CAUSE_LONGPRESS,
326 // The cause is unknown but it occurs during user input except keyboard
327 // input. E.g., an event handler of a user input event moves focus.
328 CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT,
329 // The cause is unknown but it occurs during keyboard input.
330 CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT,
332 Cause mCause;
335 * mFocusChange indicates what happened for focus.
337 enum FocusChange {
338 FOCUS_NOT_CHANGED,
339 // A content got focus.
340 GOT_FOCUS,
341 // Focused content lost focus.
342 LOST_FOCUS,
343 // Menu got pseudo focus that means focused content isn't changed but
344 // keyboard events will be handled by menu.
345 MENU_GOT_PSEUDO_FOCUS,
346 // Menu lost pseudo focus that means focused content will handle keyboard
347 // events.
348 MENU_LOST_PSEUDO_FOCUS,
349 // The widget is created. When a widget is crated, it may need to notify
350 // IME module to initialize its native IME context. In such case, this is
351 // used. I.e., this isn't used by IMEStateManager.
352 WIDGET_CREATED
354 FocusChange mFocusChange;
356 bool ContentGotFocusByTrustedCause() const {
357 return (mFocusChange == GOT_FOCUS && mCause != CAUSE_UNKNOWN);
360 bool UserMightRequestOpenVKB() const {
361 // If focus is changed, user must not request to open VKB.
362 if (mFocusChange != FOCUS_NOT_CHANGED) {
363 return false;
365 switch (mCause) {
366 // If user clicks or touches focused editor, user must request to open
367 // VKB.
368 case CAUSE_MOUSE:
369 case CAUSE_TOUCH:
370 // If script does something during a user input and that causes changing
371 // input context, user might request to open VKB. E.g., user clicks
372 // dummy editor and JS moves focus to an actual editable node. However,
373 // this should return false if the user input is a keyboard event since
374 // physical keyboard operation shouldn't cause opening VKB.
375 case CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT:
376 return true;
377 default:
378 return false;
383 * IsHandlingUserInput() returns true if it's caused by a user action directly
384 * or it's caused by script or something but it occurred while we're handling
385 * a user action. E.g., when it's caused by Element.focus() in an event
386 * handler of a user input, this returns true.
388 static bool IsHandlingUserInput(Cause aCause) {
389 switch (aCause) {
390 case CAUSE_KEY:
391 case CAUSE_MOUSE:
392 case CAUSE_TOUCH:
393 case CAUSE_LONGPRESS:
394 case CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT:
395 case CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT:
396 return true;
397 default:
398 return false;
402 bool IsHandlingUserInput() const { return IsHandlingUserInput(mCause); }
404 InputContextAction()
405 : mCause(CAUSE_UNKNOWN), mFocusChange(FOCUS_NOT_CHANGED) {}
407 explicit InputContextAction(Cause aCause,
408 FocusChange aFocusChange = FOCUS_NOT_CHANGED)
409 : mCause(aCause), mFocusChange(aFocusChange) {}
412 // IMEMessage is shared by IMEStateManager and TextComposition.
413 // Update values in GeckoEditable.java if you make changes here.
414 // XXX Negative values are used in Android...
415 typedef int8_t IMEMessageType;
416 enum IMEMessage : IMEMessageType {
417 // This is used by IMENotification internally. This means that the instance
418 // hasn't been initialized yet.
419 NOTIFY_IME_OF_NOTHING,
420 // An editable content is getting focus
421 NOTIFY_IME_OF_FOCUS,
422 // An editable content is losing focus
423 NOTIFY_IME_OF_BLUR,
424 // Selection in the focused editable content is changed
425 NOTIFY_IME_OF_SELECTION_CHANGE,
426 // Text in the focused editable content is changed
427 NOTIFY_IME_OF_TEXT_CHANGE,
428 // Notified when a dispatched composition event is handled by the
429 // contents. This must be notified after the other notifications.
430 // Note that if a remote process has focus, this is notified only once when
431 // all dispatched events are handled completely. So, the receiver shouldn't
432 // count number of received this notification for comparing with the number
433 // of dispatched events.
434 // NOTE: If a composition event causes moving focus from the focused editor,
435 // this notification may not be notified as usual. Even in such case,
436 // NOTIFY_IME_OF_BLUR is always sent. So, notification listeners
437 // should tread the blur notification as including this if there is
438 // pending composition events.
439 NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED,
440 // Position or size of focused element may be changed.
441 NOTIFY_IME_OF_POSITION_CHANGE,
442 // Mouse button event is fired on a character in focused editor
443 NOTIFY_IME_OF_MOUSE_BUTTON_EVENT,
444 // Request to commit current composition to IME
445 // (some platforms may not support)
446 REQUEST_TO_COMMIT_COMPOSITION,
447 // Request to cancel current composition to IME
448 // (some platforms may not support)
449 REQUEST_TO_CANCEL_COMPOSITION
452 // FYI: Implemented in nsBaseWidget.cpp
453 const char* ToChar(IMEMessage aIMEMessage);
455 struct IMENotification final {
456 IMENotification() : mMessage(NOTIFY_IME_OF_NOTHING), mSelectionChangeData() {}
458 IMENotification(const IMENotification& aOther)
459 : mMessage(NOTIFY_IME_OF_NOTHING) {
460 Assign(aOther);
463 ~IMENotification() { Clear(); }
465 MOZ_IMPLICIT IMENotification(IMEMessage aMessage)
466 : mMessage(aMessage), mSelectionChangeData() {
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;
489 void Assign(const IMENotification& aOther) {
490 bool changingMessage = mMessage != aOther.mMessage;
491 if (changingMessage) {
492 Clear();
493 mMessage = aOther.mMessage;
495 switch (mMessage) {
496 case NOTIFY_IME_OF_SELECTION_CHANGE:
497 if (changingMessage) {
498 mSelectionChangeData.mString = new nsString();
500 mSelectionChangeData.Assign(aOther.mSelectionChangeData);
501 break;
502 case NOTIFY_IME_OF_TEXT_CHANGE:
503 mTextChangeData = aOther.mTextChangeData;
504 break;
505 case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
506 mMouseButtonEventData = aOther.mMouseButtonEventData;
507 break;
508 default:
509 break;
513 IMENotification& operator=(const IMENotification& aOther) {
514 Assign(aOther);
515 return *this;
518 void Clear() {
519 if (mMessage == NOTIFY_IME_OF_SELECTION_CHANGE) {
520 MOZ_ASSERT(mSelectionChangeData.mString);
521 delete mSelectionChangeData.mString;
522 mSelectionChangeData.mString = nullptr;
524 mMessage = NOTIFY_IME_OF_NOTHING;
527 bool HasNotification() const { return mMessage != NOTIFY_IME_OF_NOTHING; }
529 void MergeWith(const IMENotification& aNotification) {
530 switch (mMessage) {
531 case NOTIFY_IME_OF_NOTHING:
532 MOZ_ASSERT(aNotification.mMessage != NOTIFY_IME_OF_NOTHING);
533 Assign(aNotification);
534 break;
535 case NOTIFY_IME_OF_SELECTION_CHANGE:
536 MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
537 mSelectionChangeData.Assign(aNotification.mSelectionChangeData);
538 break;
539 case NOTIFY_IME_OF_TEXT_CHANGE:
540 MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE);
541 mTextChangeData += aNotification.mTextChangeData;
542 break;
543 case NOTIFY_IME_OF_POSITION_CHANGE:
544 case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED:
545 MOZ_ASSERT(aNotification.mMessage == mMessage);
546 break;
547 default:
548 MOZ_CRASH("Merging notification isn't supported");
549 break;
553 IMEMessage mMessage;
555 struct Point {
556 int32_t mX;
557 int32_t mY;
559 void Set(const nsIntPoint& aPoint) {
560 mX = aPoint.x;
561 mY = aPoint.y;
563 nsIntPoint AsIntPoint() const { return nsIntPoint(mX, mY); }
566 struct Rect {
567 int32_t mX;
568 int32_t mY;
569 int32_t mWidth;
570 int32_t mHeight;
572 void Set(const nsIntRect& aRect) {
573 aRect.GetRect(&mX, &mY, &mWidth, &mHeight);
575 nsIntRect AsIntRect() const { return nsIntRect(mX, mY, mWidth, mHeight); }
578 // NOTIFY_IME_OF_SELECTION_CHANGE specific data
579 struct SelectionChangeDataBase {
580 // Selection range.
581 uint32_t mOffset;
583 // Selected string
584 nsString* mString;
586 // Writing mode at the selection.
587 uint8_t mWritingMode;
589 bool mReversed;
590 bool mCausedByComposition;
591 bool mCausedBySelectionEvent;
592 bool mOccurredDuringComposition;
594 void SetWritingMode(const WritingMode& aWritingMode);
595 WritingMode GetWritingMode() const;
597 uint32_t StartOffset() const {
598 return mOffset + (mReversed ? Length() : 0);
600 uint32_t EndOffset() const { return mOffset + (mReversed ? 0 : Length()); }
601 const nsString& String() const { return *mString; }
602 uint32_t Length() const { return mString->Length(); }
603 bool IsInInt32Range() const { return mOffset + Length() <= INT32_MAX; }
604 bool IsCollapsed() const { return mString->IsEmpty(); }
605 void ClearSelectionData() {
606 mOffset = UINT32_MAX;
607 mString->Truncate();
608 mWritingMode = 0;
609 mReversed = false;
611 void Clear() {
612 ClearSelectionData();
613 mCausedByComposition = false;
614 mCausedBySelectionEvent = false;
615 mOccurredDuringComposition = false;
617 bool IsValid() const { return mOffset != UINT32_MAX; }
618 void Assign(const SelectionChangeDataBase& aOther) {
619 mOffset = aOther.mOffset;
620 *mString = aOther.String();
621 mWritingMode = aOther.mWritingMode;
622 mReversed = aOther.mReversed;
623 AssignReason(aOther.mCausedByComposition, aOther.mCausedBySelectionEvent,
624 aOther.mOccurredDuringComposition);
626 void AssignReason(bool aCausedByComposition, bool aCausedBySelectionEvent,
627 bool aOccurredDuringComposition) {
628 mCausedByComposition = aCausedByComposition;
629 mCausedBySelectionEvent = aCausedBySelectionEvent;
630 mOccurredDuringComposition = aOccurredDuringComposition;
634 // SelectionChangeDataBase cannot have constructors because it's used in
635 // the union. Therefore, SelectionChangeData should only implement
636 // constructors. In other words, add other members to
637 // SelectionChangeDataBase.
638 struct SelectionChangeData final : public SelectionChangeDataBase {
639 SelectionChangeData() {
640 mString = &mStringInstance;
641 Clear();
643 explicit SelectionChangeData(const SelectionChangeDataBase& aOther) {
644 mString = &mStringInstance;
645 Assign(aOther);
647 SelectionChangeData(const SelectionChangeData& aOther) {
648 mString = &mStringInstance;
649 Assign(aOther);
651 SelectionChangeData& operator=(const SelectionChangeDataBase& aOther) {
652 mString = &mStringInstance;
653 Assign(aOther);
654 return *this;
656 SelectionChangeData& operator=(const SelectionChangeData& aOther) {
657 mString = &mStringInstance;
658 Assign(aOther);
659 return *this;
662 private:
663 // When SelectionChangeData is used outside of union, it shouldn't create
664 // nsString instance in the heap as far as possible.
665 nsString mStringInstance;
668 struct TextChangeDataBase {
669 // mStartOffset is the start offset of modified or removed text in
670 // original content and inserted text in new content.
671 uint32_t mStartOffset;
672 // mRemovalEndOffset is the end offset of modified or removed text in
673 // original content. If the value is same as mStartOffset, no text hasn't
674 // been removed yet.
675 uint32_t mRemovedEndOffset;
676 // mAddedEndOffset is the end offset of inserted text or same as
677 // mStartOffset if just removed. The vlaue is offset in the new content.
678 uint32_t mAddedEndOffset;
680 // Note that TextChangeDataBase may be the result of merging two or more
681 // changes especially in e10s mode.
683 // mCausedOnlyByComposition is true only when *all* merged changes are
684 // caused by composition.
685 bool mCausedOnlyByComposition;
686 // mIncludingChangesDuringComposition is true if at least one change which
687 // is not caused by composition occurred during the last composition.
688 // Note that if after the last composition is finished and there are some
689 // changes not caused by composition, this is set to false.
690 bool mIncludingChangesDuringComposition;
691 // mIncludingChangesWithoutComposition is true if there is at least one
692 // change which did occur when there wasn't a composition ongoing.
693 bool mIncludingChangesWithoutComposition;
695 uint32_t OldLength() const {
696 MOZ_ASSERT(IsValid());
697 return mRemovedEndOffset - mStartOffset;
699 uint32_t NewLength() const {
700 MOZ_ASSERT(IsValid());
701 return mAddedEndOffset - mStartOffset;
704 // Positive if text is added. Negative if text is removed.
705 int64_t Difference() const { return mAddedEndOffset - mRemovedEndOffset; }
707 bool IsInInt32Range() const {
708 MOZ_ASSERT(IsValid());
709 return mStartOffset <= INT32_MAX && mRemovedEndOffset <= INT32_MAX &&
710 mAddedEndOffset <= INT32_MAX;
713 bool IsValid() const {
714 return !(mStartOffset == UINT32_MAX && !mRemovedEndOffset &&
715 !mAddedEndOffset);
718 void Clear() {
719 mStartOffset = UINT32_MAX;
720 mRemovedEndOffset = mAddedEndOffset = 0;
723 void MergeWith(const TextChangeDataBase& aOther);
724 TextChangeDataBase& operator+=(const TextChangeDataBase& aOther) {
725 MergeWith(aOther);
726 return *this;
729 #ifdef DEBUG
730 void Test();
731 #endif // #ifdef DEBUG
734 // TextChangeDataBase cannot have constructors because they are used in union.
735 // Therefore, TextChangeData should only implement constructor. In other
736 // words, add other members to TextChangeDataBase.
737 struct TextChangeData : public TextChangeDataBase {
738 TextChangeData() { Clear(); }
740 TextChangeData(uint32_t aStartOffset, uint32_t aRemovedEndOffset,
741 uint32_t aAddedEndOffset, bool aCausedByComposition,
742 bool aOccurredDuringComposition) {
743 MOZ_ASSERT(aRemovedEndOffset >= aStartOffset,
744 "removed end offset must not be smaller than start offset");
745 MOZ_ASSERT(aAddedEndOffset >= aStartOffset,
746 "added end offset must not be smaller than start offset");
747 mStartOffset = aStartOffset;
748 mRemovedEndOffset = aRemovedEndOffset;
749 mAddedEndOffset = aAddedEndOffset;
750 mCausedOnlyByComposition = aCausedByComposition;
751 mIncludingChangesDuringComposition =
752 !aCausedByComposition && aOccurredDuringComposition;
753 mIncludingChangesWithoutComposition =
754 !aCausedByComposition && !aOccurredDuringComposition;
758 struct MouseButtonEventData {
759 // The value of WidgetEvent::mMessage
760 EventMessage mEventMessage;
761 // Character offset from the start of the focused editor under the cursor
762 uint32_t mOffset;
763 // Cursor position in pixels relative to the widget
764 Point mCursorPos;
765 // Character rect in pixels under the cursor relative to the widget
766 Rect mCharRect;
767 // The value of WidgetMouseEventBase::button and buttons
768 int16_t mButton;
769 int16_t mButtons;
770 // The value of WidgetInputEvent::modifiers
771 Modifiers mModifiers;
774 union {
775 // NOTIFY_IME_OF_SELECTION_CHANGE specific data
776 SelectionChangeDataBase mSelectionChangeData;
778 // NOTIFY_IME_OF_TEXT_CHANGE specific data
779 TextChangeDataBase mTextChangeData;
781 // NOTIFY_IME_OF_MOUSE_BUTTON_EVENT specific data
782 MouseButtonEventData mMouseButtonEventData;
785 void SetData(const SelectionChangeDataBase& aSelectionChangeData) {
786 MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
787 mSelectionChangeData.Assign(aSelectionChangeData);
790 void SetData(const TextChangeDataBase& aTextChangeData) {
791 MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_TEXT_CHANGE);
792 mTextChangeData = aTextChangeData;
796 struct CandidateWindowPosition {
797 // Upper left corner of the candidate window if mExcludeRect is false.
798 // Otherwise, the position currently interested. E.g., caret position.
799 LayoutDeviceIntPoint mPoint;
800 // Rect which shouldn't be overlapped with the candidate window.
801 // This is valid only when mExcludeRect is true.
802 LayoutDeviceIntRect mRect;
803 // See explanation of mPoint and mRect.
804 bool mExcludeRect;
807 std::ostream& operator<<(std::ostream& aStream,
808 const IMEState::Enabled& aEnabled);
809 std::ostream& operator<<(std::ostream& aStream, const IMEState::Open& aOpen);
810 std::ostream& operator<<(std::ostream& aStream,
811 const InputContextAction::Cause& aCause);
812 std::ostream& operator<<(std::ostream& aStream,
813 const InputContextAction::FocusChange& aFocusChange);
814 std::ostream& operator<<(std::ostream& aStream,
815 const IMENotification::SelectionChangeDataBase& aData);
816 std::ostream& operator<<(std::ostream& aStream,
817 const IMENotification::TextChangeDataBase& aData);
819 } // namespace widget
820 } // namespace mozilla
822 #endif // #ifndef mozilla_widget_IMEData_h_