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