Coverage Report

Created: 2018-09-25 14:53

/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_