Bug 1641886 [wpt PR 23851] - Support interpolating contain-intrinsic-size, a=testonly
[gecko.git] / widget / IMEData.h
blobe7708e0d800c3e6cb7b6e93030d33660e409ea47
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 "mozilla/EventForwards.h"
11 #include "nsPoint.h"
12 #include "nsRect.h"
13 #include "nsString.h"
14 #include "nsXULAppAPI.h"
15 #include "Units.h"
17 class nsIWidget;
19 namespace mozilla {
21 class WritingMode;
23 namespace widget {
25 /**
26 * Preference for receiving IME updates
28 * If mWantUpdates is not NOTIFY_NOTHING, nsTextStateManager will observe text
29 * change and/or selection change and call nsIWidget::NotifyIME() with
30 * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE.
31 * Please note that the text change observing cost is very expensive especially
32 * on an HTML editor has focus.
33 * If the IME implementation on a particular platform doesn't care about
34 * NOTIFY_IME_OF_SELECTION_CHANGE and/or NOTIFY_IME_OF_TEXT_CHANGE,
35 * they should set mWantUpdates to NOTIFY_NOTHING to avoid the cost.
36 * If the IME implementation needs notifications even while our process is
37 * deactive, it should also set NOTIFY_DURING_DEACTIVE.
39 struct IMENotificationRequests final {
40 typedef uint8_t Notifications;
42 enum : Notifications {
43 NOTIFY_NOTHING = 0,
44 NOTIFY_TEXT_CHANGE = 1 << 1,
45 NOTIFY_POSITION_CHANGE = 1 << 2,
46 // NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR is used when mouse button is pressed
47 // or released on a character in the focused editor. The notification is
48 // notified to IME as a mouse event. If it's consumed by IME, NotifyIME()
49 // returns NS_SUCCESS_EVENT_CONSUMED. Otherwise, it returns NS_OK if it's
50 // handled without any error.
51 NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR = 1 << 3,
52 // NOTE: NOTIFY_DURING_DEACTIVE isn't supported in environments where two
53 // or more compositions are possible. E.g., Mac and Linux (GTK).
54 NOTIFY_DURING_DEACTIVE = 1 << 7,
56 NOTIFY_ALL = NOTIFY_TEXT_CHANGE | NOTIFY_POSITION_CHANGE |
57 NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR,
60 IMENotificationRequests() : mWantUpdates(NOTIFY_NOTHING) {}
62 explicit IMENotificationRequests(Notifications aWantUpdates)
63 : mWantUpdates(aWantUpdates) {}
65 IMENotificationRequests operator|(
66 const IMENotificationRequests& aOther) const {
67 return IMENotificationRequests(aOther.mWantUpdates | mWantUpdates);
69 IMENotificationRequests& operator|=(const IMENotificationRequests& aOther) {
70 mWantUpdates |= aOther.mWantUpdates;
71 return *this;
73 bool operator==(const IMENotificationRequests& aOther) const {
74 return mWantUpdates == aOther.mWantUpdates;
77 bool WantTextChange() const { return !!(mWantUpdates & NOTIFY_TEXT_CHANGE); }
79 bool WantPositionChanged() const {
80 return !!(mWantUpdates & NOTIFY_POSITION_CHANGE);
83 bool WantChanges() const { return WantTextChange(); }
85 bool WantMouseButtonEventOnChar() const {
86 return !!(mWantUpdates & NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR);
89 bool WantDuringDeactive() const {
90 return !!(mWantUpdates & NOTIFY_DURING_DEACTIVE);
93 Notifications mWantUpdates;
96 /**
97 * Contains IMEStatus plus information about the current
98 * input context that the IME can use as hints if desired.
101 struct IMEState final {
103 * IME enabled states, the mEnabled value of
104 * SetInputContext()/GetInputContext() should be one value of following
105 * values.
107 * WARNING: If you change these values, you also need to edit:
108 * nsIDOMWindowUtils.idl
109 * nsContentUtils::GetWidgetStatusFromIMEStatus
111 enum Enabled {
113 * 'Disabled' means the user cannot use IME. So, the IME open state should
114 * be 'closed' during 'disabled'.
116 DISABLED,
118 * 'Enabled' means the user can use IME.
120 ENABLED,
122 * 'Password' state is a special case for the password editors.
123 * E.g., on mac, the password editors should disable the non-Roman
124 * keyboard layouts at getting focus. Thus, the password editor may have
125 * special rules on some platforms.
127 PASSWORD,
129 * This state is used when a plugin is focused.
130 * When a plug-in is focused content, we should send native events
131 * directly. Because we don't process some native events, but they may
132 * be needed by the plug-in.
134 PLUGIN,
136 * 'Unknown' is useful when you cache this enum. So, this shouldn't be
137 * used with nsIWidget::SetInputContext().
139 UNKNOWN
141 Enabled mEnabled;
144 * IME open states the mOpen value of SetInputContext() should be one value of
145 * OPEN, CLOSE or DONT_CHANGE_OPEN_STATE. GetInputContext() should return
146 * OPEN, CLOSE or OPEN_STATE_NOT_SUPPORTED.
148 enum Open {
150 * 'Unsupported' means the platform cannot return actual IME open state.
151 * This value is used only by GetInputContext().
153 OPEN_STATE_NOT_SUPPORTED,
155 * 'Don't change' means the widget shouldn't change IME open state when
156 * SetInputContext() is called.
158 DONT_CHANGE_OPEN_STATE = OPEN_STATE_NOT_SUPPORTED,
160 * 'Open' means that IME should compose in its primary language (or latest
161 * input mode except direct ASCII character input mode). Even if IME is
162 * opened by this value, users should be able to close IME by theirselves.
163 * Web contents can specify this value by |ime-mode: active;|.
165 OPEN,
167 * 'Closed' means that IME shouldn't handle key events (or should handle
168 * as ASCII character inputs on mobile device). Even if IME is closed by
169 * this value, users should be able to open IME by theirselves.
170 * Web contents can specify this value by |ime-mode: inactive;|.
172 CLOSED
174 Open mOpen;
176 IMEState() : mEnabled(ENABLED), mOpen(DONT_CHANGE_OPEN_STATE) {}
178 explicit IMEState(Enabled aEnabled, Open aOpen = DONT_CHANGE_OPEN_STATE)
179 : mEnabled(aEnabled), mOpen(aOpen) {}
181 // Returns true if the user can input characters.
182 // This means that a plain text editor, an HTML editor, a password editor or
183 // a plain text editor whose ime-mode is "disabled".
184 bool IsEditable() const {
185 return mEnabled == ENABLED || mEnabled == PASSWORD;
187 // Returns true if the user might be able to input characters.
188 // This means that a plain text editor, an HTML editor, a password editor,
189 // a plain text editor whose ime-mode is "disabled" or a windowless plugin
190 // has focus.
191 bool MaybeEditable() const { return IsEditable() || mEnabled == PLUGIN; }
194 // NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context.
195 // If there can be only one IME composition in a process, this can be used.
196 #define NS_ONLY_ONE_NATIVE_IME_CONTEXT \
197 (reinterpret_cast<void*>(static_cast<intptr_t>(-1)))
199 struct NativeIMEContext final {
200 // Pointer to native IME context. Typically this is the result of
201 // nsIWidget::GetNativeData(NS_RAW_NATIVE_IME_CONTEXT) in the parent process.
202 // See also NS_ONLY_ONE_NATIVE_IME_CONTEXT.
203 uintptr_t mRawNativeIMEContext;
204 // Process ID of the origin of mNativeIMEContext.
205 uint64_t mOriginProcessID;
207 NativeIMEContext() : mRawNativeIMEContext(0), mOriginProcessID(0) {
208 Init(nullptr);
211 explicit NativeIMEContext(nsIWidget* aWidget)
212 : mRawNativeIMEContext(0), mOriginProcessID(0) {
213 Init(aWidget);
216 bool IsValid() const {
217 return mRawNativeIMEContext &&
218 mOriginProcessID != static_cast<uintptr_t>(-1);
221 void Init(nsIWidget* aWidget);
222 void InitWithRawNativeIMEContext(const void* aRawNativeIMEContext) {
223 InitWithRawNativeIMEContext(const_cast<void*>(aRawNativeIMEContext));
225 void InitWithRawNativeIMEContext(void* aRawNativeIMEContext);
227 bool operator==(const NativeIMEContext& aOther) const {
228 return mRawNativeIMEContext == aOther.mRawNativeIMEContext &&
229 mOriginProcessID == aOther.mOriginProcessID;
231 bool operator!=(const NativeIMEContext& aOther) const {
232 return !(*this == aOther);
236 struct InputContext final {
237 InputContext()
238 : mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT),
239 mMayBeIMEUnaware(false),
240 mHasHandledUserInput(false),
241 mInPrivateBrowsing(false) {}
243 // If InputContext instance is a static variable, any heap allocated stuff
244 // of its members need to be deleted at XPCOM shutdown. Otherwise, it's
245 // detected as memory leak.
246 void ShutDown() {
247 mHTMLInputType.Truncate();
248 mHTMLInputInputmode.Truncate();
249 mActionHint.Truncate();
252 bool IsPasswordEditor() const {
253 return mHTMLInputType.LowerCaseEqualsLiteral("password");
256 IMEState mIMEState;
258 /* The type of the input if the input is a html input field */
259 nsString mHTMLInputType;
261 /* The type of the inputmode */
262 nsString mHTMLInputInputmode;
264 /* A hint for the action that is performed when the input is submitted */
265 nsString mActionHint;
268 * mOrigin indicates whether this focus event refers to main or remote
269 * content.
271 enum Origin {
272 // Adjusting focus of content on the main process
273 ORIGIN_MAIN,
274 // Adjusting focus of content in a remote process
275 ORIGIN_CONTENT
277 Origin mOrigin;
279 /* True if the webapp may be unaware of IME events such as input event or
280 * composiion events. This enables a key-events-only mode on Android for
281 * compatibility with webapps relying on key listeners. */
282 bool mMayBeIMEUnaware;
285 * True if the document has ever received user input
287 bool mHasHandledUserInput;
289 /* Whether the owning document of the input element has been loaded
290 * in private browsing mode. */
291 bool mInPrivateBrowsing;
293 bool IsOriginMainProcess() const { return mOrigin == ORIGIN_MAIN; }
295 bool IsOriginContentProcess() const { return mOrigin == ORIGIN_CONTENT; }
297 bool IsOriginCurrentProcess() const {
298 if (XRE_IsParentProcess()) {
299 return IsOriginMainProcess();
301 return IsOriginContentProcess();
305 // FYI: Implemented in nsBaseWidget.cpp
306 const char* ToChar(InputContext::Origin aOrigin);
308 struct InputContextAction final {
310 * mCause indicates what action causes calling nsIWidget::SetInputContext().
311 * It must be one of following values.
313 enum Cause {
314 // The cause is unknown but originated from content. Focus might have been
315 // changed by content script.
316 CAUSE_UNKNOWN,
317 // The cause is unknown but originated from chrome. Focus might have been
318 // changed by chrome script.
319 CAUSE_UNKNOWN_CHROME,
320 // The cause is user's keyboard operation.
321 CAUSE_KEY,
322 // The cause is user's mouse operation.
323 CAUSE_MOUSE,
324 // The cause is user's touch operation (implies mouse)
325 CAUSE_TOUCH,
326 // The cause is users' long press operation.
327 CAUSE_LONGPRESS,
328 // The cause is unknown but it occurs during user input except keyboard
329 // input. E.g., an event handler of a user input event moves focus.
330 CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT,
331 // The cause is unknown but it occurs during keyboard input.
332 CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT,
334 Cause mCause;
337 * mFocusChange indicates what happened for focus.
339 enum FocusChange {
340 FOCUS_NOT_CHANGED,
341 // A content got focus.
342 GOT_FOCUS,
343 // Focused content lost focus.
344 LOST_FOCUS,
345 // Menu got pseudo focus that means focused content isn't changed but
346 // keyboard events will be handled by menu.
347 MENU_GOT_PSEUDO_FOCUS,
348 // Menu lost pseudo focus that means focused content will handle keyboard
349 // events.
350 MENU_LOST_PSEUDO_FOCUS,
351 // The widget is created. When a widget is crated, it may need to notify
352 // IME module to initialize its native IME context. In such case, this is
353 // used. I.e., this isn't used by IMEStateManager.
354 WIDGET_CREATED
356 FocusChange mFocusChange;
358 bool ContentGotFocusByTrustedCause() const {
359 return (mFocusChange == GOT_FOCUS && mCause != CAUSE_UNKNOWN);
362 bool UserMightRequestOpenVKB() const {
363 // If focus is changed, user must not request to open VKB.
364 if (mFocusChange != FOCUS_NOT_CHANGED) {
365 return false;
367 switch (mCause) {
368 // If user clicks or touches focused editor, user must request to open
369 // VKB.
370 case CAUSE_MOUSE:
371 case CAUSE_TOUCH:
372 // If script does something during a user input and that causes changing
373 // input context, user might request to open VKB. E.g., user clicks
374 // dummy editor and JS moves focus to an actual editable node. However,
375 // this should return false if the user input is a keyboard event since
376 // physical keyboard operation shouldn't cause opening VKB.
377 case CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT:
378 return true;
379 default:
380 return false;
385 * IsHandlingUserInput() returns true if it's caused by a user action directly
386 * or it's caused by script or something but it occurred while we're handling
387 * a user action. E.g., when it's caused by Element.focus() in an event
388 * handler of a user input, this returns true.
390 static bool IsHandlingUserInput(Cause aCause) {
391 switch (aCause) {
392 case CAUSE_KEY:
393 case CAUSE_MOUSE:
394 case CAUSE_TOUCH:
395 case CAUSE_LONGPRESS:
396 case CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT:
397 case CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT:
398 return true;
399 default:
400 return false;
404 bool IsHandlingUserInput() const { return IsHandlingUserInput(mCause); }
406 InputContextAction()
407 : mCause(CAUSE_UNKNOWN), mFocusChange(FOCUS_NOT_CHANGED) {}
409 explicit InputContextAction(Cause aCause,
410 FocusChange aFocusChange = FOCUS_NOT_CHANGED)
411 : mCause(aCause), mFocusChange(aFocusChange) {}
414 // IMEMessage is shared by IMEStateManager and TextComposition.
415 // Update values in GeckoEditable.java if you make changes here.
416 // XXX Negative values are used in Android...
417 typedef int8_t IMEMessageType;
418 enum IMEMessage : IMEMessageType {
419 // This is used by IMENotification internally. This means that the instance
420 // hasn't been initialized yet.
421 NOTIFY_IME_OF_NOTHING,
422 // An editable content is getting focus
423 NOTIFY_IME_OF_FOCUS,
424 // An editable content is losing focus
425 NOTIFY_IME_OF_BLUR,
426 // Selection in the focused editable content is changed
427 NOTIFY_IME_OF_SELECTION_CHANGE,
428 // Text in the focused editable content is changed
429 NOTIFY_IME_OF_TEXT_CHANGE,
430 // Notified when a dispatched composition event is handled by the
431 // contents. This must be notified after the other notifications.
432 // Note that if a remote process has focus, this is notified only once when
433 // all dispatched events are handled completely. So, the receiver shouldn't
434 // count number of received this notification for comparing with the number
435 // of dispatched events.
436 // NOTE: If a composition event causes moving focus from the focused editor,
437 // this notification may not be notified as usual. Even in such case,
438 // NOTIFY_IME_OF_BLUR is always sent. So, notification listeners
439 // should tread the blur notification as including this if there is
440 // pending composition events.
441 NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED,
442 // Position or size of focused element may be changed.
443 NOTIFY_IME_OF_POSITION_CHANGE,
444 // Mouse button event is fired on a character in focused editor
445 NOTIFY_IME_OF_MOUSE_BUTTON_EVENT,
446 // Request to commit current composition to IME
447 // (some platforms may not support)
448 REQUEST_TO_COMMIT_COMPOSITION,
449 // Request to cancel current composition to IME
450 // (some platforms may not support)
451 REQUEST_TO_CANCEL_COMPOSITION
454 // FYI: Implemented in nsBaseWidget.cpp
455 const char* ToChar(IMEMessage aIMEMessage);
457 struct IMENotification final {
458 IMENotification() : mMessage(NOTIFY_IME_OF_NOTHING), mSelectionChangeData() {}
460 IMENotification(const IMENotification& aOther)
461 : mMessage(NOTIFY_IME_OF_NOTHING) {
462 Assign(aOther);
465 ~IMENotification() { Clear(); }
467 MOZ_IMPLICIT IMENotification(IMEMessage aMessage)
468 : mMessage(aMessage), mSelectionChangeData() {
469 switch (aMessage) {
470 case NOTIFY_IME_OF_SELECTION_CHANGE:
471 mSelectionChangeData.mString = new nsString();
472 mSelectionChangeData.Clear();
473 break;
474 case NOTIFY_IME_OF_TEXT_CHANGE:
475 mTextChangeData.Clear();
476 break;
477 case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
478 mMouseButtonEventData.mEventMessage = eVoidEvent;
479 mMouseButtonEventData.mOffset = UINT32_MAX;
480 mMouseButtonEventData.mCursorPos.Set(nsIntPoint(0, 0));
481 mMouseButtonEventData.mCharRect.Set(nsIntRect(0, 0, 0, 0));
482 mMouseButtonEventData.mButton = -1;
483 mMouseButtonEventData.mButtons = 0;
484 mMouseButtonEventData.mModifiers = 0;
485 break;
486 default:
487 break;
491 void Assign(const IMENotification& aOther) {
492 bool changingMessage = mMessage != aOther.mMessage;
493 if (changingMessage) {
494 Clear();
495 mMessage = aOther.mMessage;
497 switch (mMessage) {
498 case NOTIFY_IME_OF_SELECTION_CHANGE:
499 if (changingMessage) {
500 mSelectionChangeData.mString = new nsString();
502 mSelectionChangeData.Assign(aOther.mSelectionChangeData);
503 break;
504 case NOTIFY_IME_OF_TEXT_CHANGE:
505 mTextChangeData = aOther.mTextChangeData;
506 break;
507 case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT:
508 mMouseButtonEventData = aOther.mMouseButtonEventData;
509 break;
510 default:
511 break;
515 IMENotification& operator=(const IMENotification& aOther) {
516 Assign(aOther);
517 return *this;
520 void Clear() {
521 if (mMessage == NOTIFY_IME_OF_SELECTION_CHANGE) {
522 MOZ_ASSERT(mSelectionChangeData.mString);
523 delete mSelectionChangeData.mString;
524 mSelectionChangeData.mString = nullptr;
526 mMessage = NOTIFY_IME_OF_NOTHING;
529 bool HasNotification() const { return mMessage != NOTIFY_IME_OF_NOTHING; }
531 void MergeWith(const IMENotification& aNotification) {
532 switch (mMessage) {
533 case NOTIFY_IME_OF_NOTHING:
534 MOZ_ASSERT(aNotification.mMessage != NOTIFY_IME_OF_NOTHING);
535 Assign(aNotification);
536 break;
537 case NOTIFY_IME_OF_SELECTION_CHANGE:
538 MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
539 mSelectionChangeData.Assign(aNotification.mSelectionChangeData);
540 break;
541 case NOTIFY_IME_OF_TEXT_CHANGE:
542 MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE);
543 mTextChangeData += aNotification.mTextChangeData;
544 break;
545 case NOTIFY_IME_OF_POSITION_CHANGE:
546 case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED:
547 MOZ_ASSERT(aNotification.mMessage == mMessage);
548 break;
549 default:
550 MOZ_CRASH("Merging notification isn't supported");
551 break;
555 IMEMessage mMessage;
557 struct Point {
558 int32_t mX;
559 int32_t mY;
561 void Set(const nsIntPoint& aPoint) {
562 mX = aPoint.x;
563 mY = aPoint.y;
565 nsIntPoint AsIntPoint() const { return nsIntPoint(mX, mY); }
568 struct Rect {
569 int32_t mX;
570 int32_t mY;
571 int32_t mWidth;
572 int32_t mHeight;
574 void Set(const nsIntRect& aRect) {
575 aRect.GetRect(&mX, &mY, &mWidth, &mHeight);
577 nsIntRect AsIntRect() const { return nsIntRect(mX, mY, mWidth, mHeight); }
580 // NOTIFY_IME_OF_SELECTION_CHANGE specific data
581 struct SelectionChangeDataBase {
582 // Selection range.
583 uint32_t mOffset;
585 // Selected string
586 nsString* mString;
588 // Writing mode at the selection.
589 uint8_t mWritingMode;
591 bool mReversed;
592 bool mCausedByComposition;
593 bool mCausedBySelectionEvent;
594 bool mOccurredDuringComposition;
596 void SetWritingMode(const WritingMode& aWritingMode);
597 WritingMode GetWritingMode() const;
599 uint32_t StartOffset() const {
600 return mOffset + (mReversed ? Length() : 0);
602 uint32_t EndOffset() const { return mOffset + (mReversed ? 0 : Length()); }
603 const nsString& String() const { return *mString; }
604 uint32_t Length() const { return mString->Length(); }
605 bool IsInInt32Range() const { return mOffset + Length() <= INT32_MAX; }
606 bool IsCollapsed() const { return mString->IsEmpty(); }
607 void ClearSelectionData() {
608 mOffset = UINT32_MAX;
609 mString->Truncate();
610 mWritingMode = 0;
611 mReversed = false;
613 void Clear() {
614 ClearSelectionData();
615 mCausedByComposition = false;
616 mCausedBySelectionEvent = false;
617 mOccurredDuringComposition = false;
619 bool IsValid() const { return mOffset != UINT32_MAX; }
620 void Assign(const SelectionChangeDataBase& aOther) {
621 mOffset = aOther.mOffset;
622 *mString = aOther.String();
623 mWritingMode = aOther.mWritingMode;
624 mReversed = aOther.mReversed;
625 AssignReason(aOther.mCausedByComposition, aOther.mCausedBySelectionEvent,
626 aOther.mOccurredDuringComposition);
628 void AssignReason(bool aCausedByComposition, bool aCausedBySelectionEvent,
629 bool aOccurredDuringComposition) {
630 mCausedByComposition = aCausedByComposition;
631 mCausedBySelectionEvent = aCausedBySelectionEvent;
632 mOccurredDuringComposition = aOccurredDuringComposition;
636 // SelectionChangeDataBase cannot have constructors because it's used in
637 // the union. Therefore, SelectionChangeData should only implement
638 // constructors. In other words, add other members to
639 // SelectionChangeDataBase.
640 struct SelectionChangeData final : public SelectionChangeDataBase {
641 SelectionChangeData() {
642 mString = &mStringInstance;
643 Clear();
645 explicit SelectionChangeData(const SelectionChangeDataBase& aOther) {
646 mString = &mStringInstance;
647 Assign(aOther);
649 SelectionChangeData(const SelectionChangeData& aOther) {
650 mString = &mStringInstance;
651 Assign(aOther);
653 SelectionChangeData& operator=(const SelectionChangeDataBase& aOther) {
654 mString = &mStringInstance;
655 Assign(aOther);
656 return *this;
658 SelectionChangeData& operator=(const SelectionChangeData& aOther) {
659 mString = &mStringInstance;
660 Assign(aOther);
661 return *this;
664 private:
665 // When SelectionChangeData is used outside of union, it shouldn't create
666 // nsString instance in the heap as far as possible.
667 nsString mStringInstance;
670 struct TextChangeDataBase {
671 // mStartOffset is the start offset of modified or removed text in
672 // original content and inserted text in new content.
673 uint32_t mStartOffset;
674 // mRemovalEndOffset is the end offset of modified or removed text in
675 // original content. If the value is same as mStartOffset, no text hasn't
676 // been removed yet.
677 uint32_t mRemovedEndOffset;
678 // mAddedEndOffset is the end offset of inserted text or same as
679 // mStartOffset if just removed. The vlaue is offset in the new content.
680 uint32_t mAddedEndOffset;
682 // Note that TextChangeDataBase may be the result of merging two or more
683 // changes especially in e10s mode.
685 // mCausedOnlyByComposition is true only when *all* merged changes are
686 // caused by composition.
687 bool mCausedOnlyByComposition;
688 // mIncludingChangesDuringComposition is true if at least one change which
689 // is not caused by composition occurred during the last composition.
690 // Note that if after the last composition is finished and there are some
691 // changes not caused by composition, this is set to false.
692 bool mIncludingChangesDuringComposition;
693 // mIncludingChangesWithoutComposition is true if there is at least one
694 // change which did occur when there wasn't a composition ongoing.
695 bool mIncludingChangesWithoutComposition;
697 uint32_t OldLength() const {
698 MOZ_ASSERT(IsValid());
699 return mRemovedEndOffset - mStartOffset;
701 uint32_t NewLength() const {
702 MOZ_ASSERT(IsValid());
703 return mAddedEndOffset - mStartOffset;
706 // Positive if text is added. Negative if text is removed.
707 int64_t Difference() const { return mAddedEndOffset - mRemovedEndOffset; }
709 bool IsInInt32Range() const {
710 MOZ_ASSERT(IsValid());
711 return mStartOffset <= INT32_MAX && mRemovedEndOffset <= INT32_MAX &&
712 mAddedEndOffset <= INT32_MAX;
715 bool IsValid() const {
716 return !(mStartOffset == UINT32_MAX && !mRemovedEndOffset &&
717 !mAddedEndOffset);
720 void Clear() {
721 mStartOffset = UINT32_MAX;
722 mRemovedEndOffset = mAddedEndOffset = 0;
725 void MergeWith(const TextChangeDataBase& aOther);
726 TextChangeDataBase& operator+=(const TextChangeDataBase& aOther) {
727 MergeWith(aOther);
728 return *this;
731 #ifdef DEBUG
732 void Test();
733 #endif // #ifdef DEBUG
736 // TextChangeDataBase cannot have constructors because they are used in union.
737 // Therefore, TextChangeData should only implement constructor. In other
738 // words, add other members to TextChangeDataBase.
739 struct TextChangeData : public TextChangeDataBase {
740 TextChangeData() { Clear(); }
742 TextChangeData(uint32_t aStartOffset, uint32_t aRemovedEndOffset,
743 uint32_t aAddedEndOffset, bool aCausedByComposition,
744 bool aOccurredDuringComposition) {
745 MOZ_ASSERT(aRemovedEndOffset >= aStartOffset,
746 "removed end offset must not be smaller than start offset");
747 MOZ_ASSERT(aAddedEndOffset >= aStartOffset,
748 "added end offset must not be smaller than start offset");
749 mStartOffset = aStartOffset;
750 mRemovedEndOffset = aRemovedEndOffset;
751 mAddedEndOffset = aAddedEndOffset;
752 mCausedOnlyByComposition = aCausedByComposition;
753 mIncludingChangesDuringComposition =
754 !aCausedByComposition && aOccurredDuringComposition;
755 mIncludingChangesWithoutComposition =
756 !aCausedByComposition && !aOccurredDuringComposition;
760 struct MouseButtonEventData {
761 // The value of WidgetEvent::mMessage
762 EventMessage mEventMessage;
763 // Character offset from the start of the focused editor under the cursor
764 uint32_t mOffset;
765 // Cursor position in pixels relative to the widget
766 Point mCursorPos;
767 // Character rect in pixels under the cursor relative to the widget
768 Rect mCharRect;
769 // The value of WidgetMouseEventBase::button and buttons
770 int16_t mButton;
771 int16_t mButtons;
772 // The value of WidgetInputEvent::modifiers
773 Modifiers mModifiers;
776 union {
777 // NOTIFY_IME_OF_SELECTION_CHANGE specific data
778 SelectionChangeDataBase mSelectionChangeData;
780 // NOTIFY_IME_OF_TEXT_CHANGE specific data
781 TextChangeDataBase mTextChangeData;
783 // NOTIFY_IME_OF_MOUSE_BUTTON_EVENT specific data
784 MouseButtonEventData mMouseButtonEventData;
787 void SetData(const SelectionChangeDataBase& aSelectionChangeData) {
788 MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
789 mSelectionChangeData.Assign(aSelectionChangeData);
792 void SetData(const TextChangeDataBase& aTextChangeData) {
793 MOZ_RELEASE_ASSERT(mMessage == NOTIFY_IME_OF_TEXT_CHANGE);
794 mTextChangeData = aTextChangeData;
798 struct CandidateWindowPosition {
799 // Upper left corner of the candidate window if mExcludeRect is false.
800 // Otherwise, the position currently interested. E.g., caret position.
801 LayoutDeviceIntPoint mPoint;
802 // Rect which shouldn't be overlapped with the candidate window.
803 // This is valid only when mExcludeRect is true.
804 LayoutDeviceIntRect mRect;
805 // See explanation of mPoint and mRect.
806 bool mExcludeRect;
809 std::ostream& operator<<(std::ostream& aStream,
810 const IMEState::Enabled& aEnabled);
811 std::ostream& operator<<(std::ostream& aStream, const IMEState::Open& aOpen);
812 std::ostream& operator<<(std::ostream& aStream,
813 const InputContextAction::Cause& aCause);
814 std::ostream& operator<<(std::ostream& aStream,
815 const InputContextAction::FocusChange& aFocusChange);
816 std::ostream& operator<<(std::ostream& aStream,
817 const IMENotification::SelectionChangeDataBase& aData);
818 std::ostream& operator<<(std::ostream& aStream,
819 const IMENotification::TextChangeDataBase& aData);
821 } // namespace widget
822 } // namespace mozilla
824 #endif // #ifndef mozilla_widget_IMEData_h_