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