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