Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/IMEStateManager.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_IMEStateManager_h_
8
#define mozilla_IMEStateManager_h_
9
10
#include "mozilla/EventForwards.h"
11
#include "mozilla/StaticPtr.h"
12
#include "mozilla/dom/TabParent.h"
13
#include "nsIWidget.h"
14
15
class nsIContent;
16
class nsINode;
17
class nsPresContext;
18
19
namespace mozilla {
20
21
class EditorBase;
22
class EventDispatchingCallback;
23
class IMEContentObserver;
24
class TextCompositionArray;
25
class TextComposition;
26
27
namespace dom {
28
class Selection;
29
} // namespace dom
30
31
/**
32
 * IMEStateManager manages InputContext (e.g., active editor type, IME enabled
33
 * state and IME open state) of nsIWidget instances, manages IMEContentObserver
34
 * and provides useful API for IME.
35
 */
36
37
class IMEStateManager
38
{
39
  typedef dom::TabParent TabParent;
40
  typedef widget::IMEMessage IMEMessage;
41
  typedef widget::IMENotification IMENotification;
42
  typedef widget::IMEState IMEState;
43
  typedef widget::InputContext InputContext;
44
  typedef widget::InputContextAction InputContextAction;
45
46
public:
47
  static void Init();
48
  static void Shutdown();
49
50
  /**
51
   * GetActiveTabParent() returns a pointer to a TabParent instance which is
52
   * managed by the focused content (sContent).  If the focused content isn't
53
   * managing another process, this returns nullptr.
54
   */
55
  static TabParent* GetActiveTabParent()
56
0
  {
57
0
    // If menu has pseudo focus, we should ignore active child process.
58
0
    if (sInstalledMenuKeyboardListener) {
59
0
      return nullptr;
60
0
    }
61
0
    return sActiveTabParent.get();
62
0
  }
63
64
  /**
65
   * DoesTabParentHaveIMEFocus() returns true when aTabParent has IME focus,
66
   * i.e., the TabParent sent "focus" notification but not yet sends "blur".
67
   * Note that this doesn't check if the remote processes are same because
68
   * if another TabParent has focus, committing composition causes firing
69
   * composition events in different TabParent.  (Anyway, such case shouldn't
70
   * occur.)
71
   */
72
  static bool DoesTabParentHaveIMEFocus(const TabParent* aTabParent)
73
0
  {
74
0
    MOZ_ASSERT(aTabParent);
75
0
    return sFocusedIMETabParent == aTabParent;
76
0
  }
77
78
  /**
79
   * OnTabParentDestroying() is called when aTabParent is being destroyed.
80
   */
81
  static void OnTabParentDestroying(TabParent* aTabParent);
82
83
  /**
84
   * Called when aWidget is being deleted.
85
   */
86
  static void WidgetDestroyed(nsIWidget* aWidget);
87
88
  /**
89
   * GetWidgetForActiveInputContext() returns a widget which IMEStateManager
90
   * is managing input context with.  If a widget instance needs to cache
91
   * the last input context for nsIWidget::GetInputContext() or something,
92
   * it should check if its cache is valid with this method before using it
93
   * because if this method returns another instance, it means that
94
   * IMEStateManager may have already changed shared input context via the
95
   * widget.
96
   */
97
  static nsIWidget* GetWidgetForActiveInputContext()
98
0
  {
99
0
    return sActiveInputContextWidget;
100
0
  }
101
102
  /**
103
   * SetIMEContextForChildProcess() is called when aTabParent receives
104
   * SetInputContext() from the remote process.
105
   */
106
  static void SetInputContextForChildProcess(TabParent* aTabParent,
107
                                             const InputContext& aInputContext,
108
                                             const InputContextAction& aAction);
109
110
  /**
111
   * StopIMEStateManagement() is called when the process should stop managing
112
   * IME state.
113
   */
114
  static void StopIMEStateManagement();
115
116
  /**
117
   * MaybeStartOffsetUpdatedInChild() is called when composition start offset
118
   * is maybe updated in the child process.  I.e., even if it's not updated,
119
   * this is called and never called if the composition is in this process.
120
   * @param aWidget             The widget whose native IME context has the
121
   *                            composition.
122
   * @param aStartOffset        New composition start offset with native
123
   *                            linebreaks.
124
   */
125
  static void MaybeStartOffsetUpdatedInChild(nsIWidget* aWidget,
126
                                             uint32_t aStartOffset);
127
128
  static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
129
  static nsresult OnRemoveContent(nsPresContext* aPresContext,
130
                                  nsIContent* aContent);
131
  /**
132
   * OnChangeFocus() should be called when focused content is changed or
133
   * IME enabled state is changed.  If nobody has focus, set both aPresContext
134
   * and aContent nullptr.  E.g., all windows are deactivated.
135
   */
136
  static nsresult OnChangeFocus(nsPresContext* aPresContext,
137
                                nsIContent* aContent,
138
                                InputContextAction::Cause aCause);
139
140
  /**
141
   * OnInstalledMenuKeyboardListener() is called when menu keyboard listener
142
   * is installed or uninstalled in the process.  So, even if menu keyboard
143
   * listener was installed in chrome process, this won't be called in content
144
   * processes.
145
   *
146
   * @param aInstalling     true if menu keyboard listener is installed.
147
   *                        Otherwise, i.e., menu keyboard listener is
148
   *                        uninstalled, false.
149
   */
150
  static void OnInstalledMenuKeyboardListener(bool aInstalling);
151
152
  // These two methods manage focus and selection/text observers.
153
  // They are separate from OnChangeFocus above because this offers finer
154
  // control compared to having the two methods incorporated into OnChangeFocus
155
156
  // Get the focused editor's selection and root
157
  static nsresult GetFocusSelectionAndRoot(dom::Selection** aSel,
158
                                           nsIContent** aRoot);
159
  // This method updates the current IME state.  However, if the enabled state
160
  // isn't changed by the new state, this method does nothing.
161
  // Note that this method changes the IME state of the active element in the
162
  // widget.  So, the caller must have focus.
163
  static void UpdateIMEState(const IMEState &aNewIMEState,
164
                             nsIContent* aContent,
165
                             EditorBase* aEditorBase);
166
167
  // This method is called when user operates mouse button in focused editor
168
  // and before the editor handles it.
169
  // Returns true if IME consumes the event.  Otherwise, false.
170
  static bool OnMouseButtonEventInEditor(nsPresContext* aPresContext,
171
                                         nsIContent* aContent,
172
                                         WidgetMouseEvent* aMouseEvent);
173
174
  // This method is called when user clicked in an editor.
175
  // aContent must be:
176
  //   If the editor is for <input> or <textarea>, the element.
177
  //   If the editor is for contenteditable, the active editinghost.
178
  //   If the editor is for designMode, nullptr.
179
  static void OnClickInEditor(nsPresContext* aPresContext,
180
                              nsIContent* aContent,
181
                              const WidgetMouseEvent* aMouseEvent);
182
183
  // This method is called when editor actually gets focus.
184
  // aContent must be:
185
  //   If the editor is for <input> or <textarea>, the element.
186
  //   If the editor is for contenteditable, the active editinghost.
187
  //   If the editor is for designMode, nullptr.
188
  static void OnFocusInEditor(nsPresContext* aPresContext,
189
                              nsIContent* aContent,
190
                              EditorBase& aEditorBase);
191
192
  // This method is called when the editor is initialized.
193
  static void OnEditorInitialized(EditorBase& aEditorBase);
194
195
  // This method is called when the editor is (might be temporarily) being
196
  // destroyed.
197
  static void OnEditorDestroying(EditorBase& aEditorBase);
198
199
  /**
200
   * All composition events must be dispatched via DispatchCompositionEvent()
201
   * for storing the composition target and ensuring a set of composition
202
   * events must be fired the stored target.  If the stored composition event
203
   * target is destroying, this removes the stored composition automatically.
204
   */
205
  static void DispatchCompositionEvent(
206
                nsINode* aEventTargetNode,
207
                nsPresContext* aPresContext,
208
                WidgetCompositionEvent* aCompositionEvent,
209
                nsEventStatus* aStatus,
210
                EventDispatchingCallback* aCallBack,
211
                bool aIsSynthesized = false);
212
213
  /**
214
   * All selection events must be handled via HandleSelectionEvent()
215
   * because they must be handled by same target as composition events when
216
   * there is a composition.
217
   */
218
  static void HandleSelectionEvent(nsPresContext* aPresContext,
219
                                   nsIContent* aEventTargetContent,
220
                                   WidgetSelectionEvent* aSelectionEvent);
221
222
  /**
223
   * This is called when PresShell ignores a composition event due to not safe
224
   * to dispatch events.
225
   */
226
  static void OnCompositionEventDiscarded(
227
                WidgetCompositionEvent* aCompositionEvent);
228
229
  /**
230
   * Get TextComposition from widget.
231
   */
232
  static already_AddRefed<TextComposition>
233
    GetTextCompositionFor(nsIWidget* aWidget);
234
235
  /**
236
   * Returns TextComposition instance for the event.
237
   */
238
  static already_AddRefed<TextComposition>
239
    GetTextCompositionFor(const WidgetCompositionEvent* aCompositionEvent);
240
241
  /**
242
   * Returns TextComposition instance for the pres context.
243
   * Be aware, even if another pres context which shares native IME context with
244
   * specified pres context has composition, this returns nullptr.
245
   */
246
  static already_AddRefed<TextComposition>
247
    GetTextCompositionFor(nsPresContext* aPresContext);
248
249
  /**
250
   * Send a notification to IME.  It depends on the IME or platform spec what
251
   * will occur (or not occur).
252
   */
253
  static nsresult NotifyIME(const IMENotification& aNotification,
254
                            nsIWidget* aWidget,
255
                            TabParent* aTabParent = nullptr);
256
  static nsresult NotifyIME(IMEMessage aMessage,
257
                            nsIWidget* aWidget,
258
                            TabParent* aTabParent = nullptr);
259
  static nsresult NotifyIME(IMEMessage aMessage,
260
                            nsPresContext* aPresContext,
261
                            TabParent* aTabParent = nullptr);
262
263
  static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
264
                                      nsIContent* aContent);
265
266
  /**
267
   * Returns active IMEContentObserver but may be nullptr if focused content
268
   * isn't editable or focus in a remote process.
269
   */
270
  static IMEContentObserver* GetActiveContentObserver();
271
272
protected:
273
  static nsresult OnChangeFocusInternal(nsPresContext* aPresContext,
274
                                        nsIContent* aContent,
275
                                        InputContextAction aAction);
276
  static void SetIMEState(const IMEState &aState,
277
                          nsPresContext* aPresContext,
278
                          nsIContent* aContent,
279
                          nsIWidget* aWidget,
280
                          InputContextAction aAction,
281
                          InputContext::Origin aOrigin);
282
  static void SetInputContext(nsIWidget* aWidget,
283
                              const InputContext& aInputContext,
284
                              const InputContextAction& aAction);
285
  static IMEState GetNewIMEState(nsPresContext* aPresContext,
286
                                 nsIContent* aContent);
287
288
  static void EnsureTextCompositionArray();
289
  static void CreateIMEContentObserver(EditorBase* aEditorBase);
290
  static void DestroyIMEContentObserver();
291
292
  /**
293
   * NotifyIMEOfBlurForChildProcess() tries to send blur notification when
294
   * a remote process has IME focus.  Otherwise, do nothing.
295
   */
296
  static void NotifyIMEOfBlurForChildProcess();
297
298
  static bool IsEditable(nsINode* node);
299
300
  static bool IsIMEObserverNeeded(const IMEState& aState);
301
302
  static nsIContent* GetRootContent(nsPresContext* aPresContext);
303
304
  /**
305
   * CanHandleWith() returns false if aPresContext is nullptr or it's destroyed.
306
   */
307
  static bool CanHandleWith(nsPresContext* aPresContext);
308
309
  /**
310
   * ResetActiveChildInputContext() resets sActiveChildInputContext.
311
   * So, HasActiveChildSetInputContext() will return false until a remote
312
   * process gets focus and set input context.
313
   */
314
  static void ResetActiveChildInputContext();
315
316
  /**
317
   * HasActiveChildSetInputContext() returns true if a remote tab has focus
318
   * and it has already set input context.  Otherwise, returns false.
319
   */
320
  static bool HasActiveChildSetInputContext();
321
322
  // sContent and sPresContext are the focused content and PresContext.  If a
323
  // document has focus but there is no focused element, sContent may be
324
  // nullptr.
325
  static StaticRefPtr<nsIContent> sContent;
326
  static StaticRefPtr<nsPresContext> sPresContext;
327
  // sWidget is cache for the root widget of sPresContext.  Even afer
328
  // sPresContext has gone, we need to clean up some IME state on the widget
329
  // if the widget is available.
330
  static nsIWidget* sWidget;
331
  // sFocusedIMETabParent is the tab parent, which send "focus" notification to
332
  // sFocusedIMEWidget (and didn't yet sent "blur" notification).
333
  static nsIWidget* sFocusedIMEWidget;
334
  static StaticRefPtr<TabParent> sFocusedIMETabParent;
335
  // sActiveInputContextWidget is the last widget whose SetInputContext() is
336
  // called.  This is important to reduce sync IPC cost with parent process.
337
  // If IMEStateManager set input context to different widget, PuppetWidget can
338
  // return cached input context safely.
339
  static nsIWidget* sActiveInputContextWidget;
340
  static StaticRefPtr<TabParent> sActiveTabParent;
341
  // sActiveIMEContentObserver points to the currently active
342
  // IMEContentObserver.  This is null if there is no focused editor.
343
  static StaticRefPtr<IMEContentObserver> sActiveIMEContentObserver;
344
345
  // All active compositions in the process are stored by this array.
346
  // When you get an item of this array and use it, please be careful.
347
  // The instances in this array can be destroyed automatically if you do
348
  // something to cause committing or canceling the composition.
349
  static TextCompositionArray* sTextCompositions;
350
351
  // Origin type of current process.
352
  static InputContext::Origin sOrigin;
353
354
  // sActiveChildInputContext is valid only when sActiveTabParent is not
355
  // nullptr.  This stores last information of input context in the remote
356
  // process of sActiveTabParent.  I.e., they are set when
357
  // SetInputContextForChildProcess() is called.  This is necessary for
358
  // restoring IME state when menu keyboard listener is uninstalled.
359
  static InputContext sActiveChildInputContext;
360
361
  // sInstalledMenuKeyboardListener is true if menu keyboard listener is
362
  // installed in the process.
363
  static bool sInstalledMenuKeyboardListener;
364
365
  static bool sIsGettingNewIMEState;
366
  static bool sCheckForIMEUnawareWebApps;
367
  static bool sInputModeSupported;
368
369
  class MOZ_STACK_CLASS GettingNewIMEStateBlocker final
370
  {
371
  public:
372
    GettingNewIMEStateBlocker()
373
      : mOldValue(IMEStateManager::sIsGettingNewIMEState)
374
0
    {
375
0
      IMEStateManager::sIsGettingNewIMEState = true;
376
0
    }
377
    ~GettingNewIMEStateBlocker()
378
0
    {
379
0
      IMEStateManager::sIsGettingNewIMEState = mOldValue;
380
0
    }
381
  private:
382
    bool mOldValue;
383
  };
384
};
385
386
} // namespace mozilla
387
388
#endif // mozilla_IMEStateManager_h_