/work/obj-fuzz/dist/include/mozilla/TextEvents.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
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_TextEvents_h__ |
7 | | #define mozilla_TextEvents_h__ |
8 | | |
9 | | #include <stdint.h> |
10 | | |
11 | | #include "mozilla/Assertions.h" |
12 | | #include "mozilla/BasicEvents.h" |
13 | | #include "mozilla/CheckedInt.h" |
14 | | #include "mozilla/EventForwards.h" // for KeyNameIndex, temporarily |
15 | | #include "mozilla/FontRange.h" |
16 | | #include "mozilla/TextRange.h" |
17 | | #include "mozilla/WritingModes.h" |
18 | | #include "mozilla/dom/KeyboardEventBinding.h" |
19 | | #include "nsCOMPtr.h" |
20 | | #include "nsISelectionController.h" |
21 | | #include "nsISelectionListener.h" |
22 | | #include "nsITransferable.h" |
23 | | #include "nsRect.h" |
24 | | #include "nsString.h" |
25 | | #include "nsTArray.h" |
26 | | |
27 | | class nsStringHashKey; |
28 | | template<class, class> class nsDataHashtable; |
29 | | |
30 | | /****************************************************************************** |
31 | | * virtual keycode values |
32 | | ******************************************************************************/ |
33 | | |
34 | | enum |
35 | | { |
36 | | #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode, |
37 | | #include "mozilla/VirtualKeyCodeList.h" |
38 | | #undef NS_DEFINE_VK |
39 | | NS_VK_UNKNOWN = 0xFF |
40 | | }; |
41 | | |
42 | | namespace mozilla { |
43 | | |
44 | | enum : uint32_t |
45 | | { |
46 | | eKeyLocationStandard = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_STANDARD, |
47 | | eKeyLocationLeft = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_LEFT, |
48 | | eKeyLocationRight = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_RIGHT, |
49 | | eKeyLocationNumpad = dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_NUMPAD |
50 | | }; |
51 | | |
52 | | const nsCString GetDOMKeyCodeName(uint32_t aKeyCode); |
53 | | |
54 | | namespace dom { |
55 | | class PBrowserParent; |
56 | | class PBrowserChild; |
57 | | } // namespace dom |
58 | | namespace plugins { |
59 | | class PPluginInstanceChild; |
60 | | } // namespace plugins |
61 | | |
62 | | enum class AccessKeyType |
63 | | { |
64 | | // Handle access key for chrome. |
65 | | eChrome, |
66 | | // Handle access key for content. |
67 | | eContent, |
68 | | // Don't handle access key. |
69 | | eNone |
70 | | }; |
71 | | |
72 | | /****************************************************************************** |
73 | | * mozilla::AlternativeCharCode |
74 | | * |
75 | | * This stores alternative charCode values of a key event with some modifiers. |
76 | | * The stored values proper for testing shortcut key or access key. |
77 | | ******************************************************************************/ |
78 | | |
79 | | struct AlternativeCharCode |
80 | | { |
81 | | AlternativeCharCode() : |
82 | | mUnshiftedCharCode(0), mShiftedCharCode(0) |
83 | 0 | { |
84 | 0 | } |
85 | | AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode) : |
86 | | mUnshiftedCharCode(aUnshiftedCharCode), mShiftedCharCode(aShiftedCharCode) |
87 | 0 | { |
88 | 0 | } |
89 | | uint32_t mUnshiftedCharCode; |
90 | | uint32_t mShiftedCharCode; |
91 | | }; |
92 | | |
93 | | /****************************************************************************** |
94 | | * mozilla::ShortcutKeyCandidate |
95 | | * |
96 | | * This stores a candidate of shortcut key combination. |
97 | | ******************************************************************************/ |
98 | | |
99 | | struct ShortcutKeyCandidate |
100 | | { |
101 | | ShortcutKeyCandidate() |
102 | | : mCharCode(0) |
103 | | , mIgnoreShift(0) |
104 | 0 | { |
105 | 0 | } |
106 | | ShortcutKeyCandidate(uint32_t aCharCode, bool aIgnoreShift) |
107 | | : mCharCode(aCharCode) |
108 | | , mIgnoreShift(aIgnoreShift) |
109 | 0 | { |
110 | 0 | } |
111 | | // The mCharCode value which must match keyboard shortcut definition. |
112 | | uint32_t mCharCode; |
113 | | // true if Shift state can be ignored. Otherwise, Shift key state must |
114 | | // match keyboard shortcut definition. |
115 | | bool mIgnoreShift; |
116 | | }; |
117 | | |
118 | | /****************************************************************************** |
119 | | * mozilla::IgnoreModifierState |
120 | | * |
121 | | * This stores flags for modifiers that should be ignored when matching |
122 | | * XBL handlers. |
123 | | ******************************************************************************/ |
124 | | |
125 | | struct IgnoreModifierState |
126 | | { |
127 | | // When mShift is true, Shift key state will be ignored. |
128 | | bool mShift; |
129 | | // When mOS is true, OS key state will be ignored. |
130 | | bool mOS; |
131 | | |
132 | | IgnoreModifierState() |
133 | | : mShift(false) |
134 | | , mOS(false) |
135 | 0 | { |
136 | 0 | } |
137 | | }; |
138 | | |
139 | | /****************************************************************************** |
140 | | * mozilla::WidgetKeyboardEvent |
141 | | ******************************************************************************/ |
142 | | |
143 | | class WidgetKeyboardEvent : public WidgetInputEvent |
144 | | { |
145 | | private: |
146 | | friend class dom::PBrowserParent; |
147 | | friend class dom::PBrowserChild; |
148 | | friend struct IPC::ParamTraits<WidgetKeyboardEvent>; |
149 | | |
150 | | protected: |
151 | | WidgetKeyboardEvent() |
152 | | : mNativeKeyEvent(nullptr) |
153 | | , mKeyCode(0) |
154 | | , mCharCode(0) |
155 | | , mPseudoCharCode(0) |
156 | | , mLocation(eKeyLocationStandard) |
157 | | , mUniqueId(0) |
158 | | #ifdef XP_MACOSX |
159 | | , mNativeModifierFlags(0) |
160 | | , mNativeKeyCode(0) |
161 | | #endif // #ifdef XP_MACOSX |
162 | | , mKeyNameIndex(KEY_NAME_INDEX_Unidentified) |
163 | | , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN) |
164 | | , mIsRepeat(false) |
165 | | , mIsComposing(false) |
166 | | , mIsSynthesizedByTIP(false) |
167 | | , mMaybeSkippableInRemoteProcess(true) |
168 | | , mEditCommandsForSingleLineEditorInitialized(false) |
169 | | , mEditCommandsForMultiLineEditorInitialized(false) |
170 | | , mEditCommandsForRichTextEditorInitialized(false) |
171 | 0 | { |
172 | 0 | } |
173 | | |
174 | | public: |
175 | 0 | virtual WidgetKeyboardEvent* AsKeyboardEvent() override { return this; } |
176 | | |
177 | | WidgetKeyboardEvent(bool aIsTrusted, EventMessage aMessage, |
178 | | nsIWidget* aWidget, |
179 | | EventClassID aEventClassID = eKeyboardEventClass) |
180 | | : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID) |
181 | | , mNativeKeyEvent(nullptr) |
182 | | , mKeyCode(0) |
183 | | , mCharCode(0) |
184 | | , mPseudoCharCode(0) |
185 | | , mLocation(eKeyLocationStandard) |
186 | | , mUniqueId(0) |
187 | | #ifdef XP_MACOSX |
188 | | , mNativeModifierFlags(0) |
189 | | , mNativeKeyCode(0) |
190 | | #endif // #ifdef XP_MACOSX |
191 | | , mKeyNameIndex(KEY_NAME_INDEX_Unidentified) |
192 | | , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN) |
193 | | , mIsRepeat(false) |
194 | | , mIsComposing(false) |
195 | | , mIsSynthesizedByTIP(false) |
196 | | , mMaybeSkippableInRemoteProcess(true) |
197 | | , mEditCommandsForSingleLineEditorInitialized(false) |
198 | | , mEditCommandsForMultiLineEditorInitialized(false) |
199 | | , mEditCommandsForRichTextEditorInitialized(false) |
200 | 0 | { |
201 | 0 | // If this is a keyboard event on a plugin, it shouldn't fired on content. |
202 | 0 | if (IsKeyEventOnPlugin()) { |
203 | 0 | mFlags.mOnlySystemGroupDispatchInContent = true; |
204 | 0 | StopCrossProcessForwarding(); |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | static bool IsKeyDownOrKeyDownOnPlugin(EventMessage aMessage) |
209 | 0 | { |
210 | 0 | return aMessage == eKeyDown || aMessage == eKeyDownOnPlugin; |
211 | 0 | } |
212 | | bool IsKeyDownOrKeyDownOnPlugin() const |
213 | 0 | { |
214 | 0 | return IsKeyDownOrKeyDownOnPlugin(mMessage); |
215 | 0 | } |
216 | | static bool IsKeyUpOrKeyUpOnPlugin(EventMessage aMessage) |
217 | 0 | { |
218 | 0 | return aMessage == eKeyUp || aMessage == eKeyUpOnPlugin; |
219 | 0 | } |
220 | | bool IsKeyUpOrKeyUpOnPlugin() const |
221 | 0 | { |
222 | 0 | return IsKeyUpOrKeyUpOnPlugin(mMessage); |
223 | 0 | } |
224 | | static bool IsKeyEventOnPlugin(EventMessage aMessage) |
225 | 0 | { |
226 | 0 | return aMessage == eKeyDownOnPlugin || aMessage == eKeyUpOnPlugin; |
227 | 0 | } |
228 | | bool IsKeyEventOnPlugin() const |
229 | 0 | { |
230 | 0 | return IsKeyEventOnPlugin(mMessage); |
231 | 0 | } |
232 | | |
233 | | // IsInputtingText() and IsInputtingLineBreak() are used to check if |
234 | | // it should cause eKeyPress events even on web content. |
235 | | // UI Events defines that "keypress" event should be fired "if and only if |
236 | | // that key normally produces a character value". |
237 | | // <https://www.w3.org/TR/uievents/#event-type-keypress> |
238 | | // Additionally, for backward compatiblity with all existing browsers, |
239 | | // there is a spec issue for Enter key press. |
240 | | // <https://github.com/w3c/uievents/issues/183> |
241 | | bool IsInputtingText() const |
242 | 0 | { |
243 | 0 | // NOTE: On some keyboard layout, some characters are inputted with Control |
244 | 0 | // key or Alt key, but at that time, widget clears the modifier flag |
245 | 0 | // from eKeyPress event because our TextEditor won't handle eKeyPress |
246 | 0 | // events as inputting text (bug 1346832). |
247 | 0 | // NOTE: There are some complicated issues of our traditional behavior. |
248 | 0 | // -- On Windows, KeyboardLayout::WillDispatchKeyboardEvent() clears |
249 | 0 | // MODIFIER_ALT and MODIFIER_CONTROL of eKeyPress event if it |
250 | 0 | // should be treated as inputting a character because AltGr is |
251 | 0 | // represented with both Alt key and Ctrl key are pressed, and |
252 | 0 | // some keyboard layouts may produces a character with Ctrl key. |
253 | 0 | // -- On Linux, KeymapWrapper doesn't have this hack since perhaps, |
254 | 0 | // we don't have any bug reports that user cannot input proper |
255 | 0 | // character with Alt and/or Ctrl key. |
256 | 0 | // -- On macOS, IMEInputHandler::WillDispatchKeyboardEvent() clears |
257 | 0 | // MODIFIER_ALT and MDOFIEIR_CONTROL of eKeyPress event only when |
258 | 0 | // TextInputHandler::InsertText() has been called for the event. |
259 | 0 | // I.e., they are cleared only when an editor has focus (even if IME |
260 | 0 | // is disabled in password field or by |ime-mode: disabled;|) because |
261 | 0 | // TextInputHandler::InsertText() is called while |
262 | 0 | // TextInputHandler::HandleKeyDownEvent() calls interpretKeyEvents: |
263 | 0 | // to notify text input processor of Cocoa (including IME). In other |
264 | 0 | // words, when we need to disable IME completey when no editor has |
265 | 0 | // focus, we cannot call interpretKeyEvents:. So, |
266 | 0 | // TextInputHandler::InsertText() won't be called when no editor has |
267 | 0 | // focus so that neither MODIFIER_ALT nor MODIFIER_CONTROL is |
268 | 0 | // cleared. So, fortunately, altKey and ctrlKey values of "keypress" |
269 | 0 | // events are same as the other browsers only when no editor has |
270 | 0 | // focus. |
271 | 0 | // NOTE: As mentioned above, for compatibility with the other browsers on |
272 | 0 | // macOS, we should keep MODIFIER_ALT and MODIFIER_CONTROL flags of |
273 | 0 | // eKeyPress events when no editor has focus. However, Alt key, |
274 | 0 | // labeled "option" on keyboard for Mac, is AltGraph key on the other |
275 | 0 | // platforms. So, even if MODIFIER_ALT is set, we need to dispatch |
276 | 0 | // eKeyPress event even on web content unless mCharCode is 0. |
277 | 0 | // Therefore, we need to ignore MODIFIER_ALT flag here only on macOS. |
278 | 0 | return mMessage == eKeyPress && |
279 | 0 | mCharCode && |
280 | 0 | !(mModifiers & ( |
281 | 0 | #ifndef XP_MACOSX |
282 | 0 | // So, ignore MODIFIER_ALT only on macOS since |
283 | 0 | // option key is used as AltGraph key on macOS. |
284 | 0 | MODIFIER_ALT | |
285 | 0 | #endif // #ifndef XP_MAXOSX |
286 | 0 | MODIFIER_CONTROL | |
287 | 0 | MODIFIER_META | |
288 | 0 | MODIFIER_OS)); |
289 | 0 | } |
290 | | |
291 | | bool IsInputtingLineBreak() const |
292 | 0 | { |
293 | 0 | return mMessage == eKeyPress && |
294 | 0 | mKeyNameIndex == KEY_NAME_INDEX_Enter && |
295 | 0 | !(mModifiers & (MODIFIER_ALT | |
296 | 0 | MODIFIER_CONTROL | |
297 | 0 | MODIFIER_META | |
298 | 0 | MODIFIER_OS)); |
299 | 0 | } |
300 | | |
301 | | /** |
302 | | * ShouldKeyPressEventBeFiredOnContent() should be called only when the |
303 | | * instance is eKeyPress event. This returns true when the eKeyPress |
304 | | * event should be fired even on content in the default event group. |
305 | | */ |
306 | | bool ShouldKeyPressEventBeFiredOnContent() const |
307 | 0 | { |
308 | 0 | MOZ_DIAGNOSTIC_ASSERT(mMessage == eKeyPress); |
309 | 0 | if (IsInputtingText() || IsInputtingLineBreak()) { |
310 | 0 | return true; |
311 | 0 | } |
312 | 0 | // Ctrl + Enter won't cause actual input in our editor. |
313 | 0 | // However, the other browsers fire keypress event in any platforms. |
314 | 0 | // So, for compatibility with them, we should fire keypress event for |
315 | 0 | // Ctrl + Enter too. |
316 | 0 | return mMessage == eKeyPress && |
317 | 0 | mKeyNameIndex == KEY_NAME_INDEX_Enter && |
318 | 0 | !(mModifiers & (MODIFIER_ALT | |
319 | 0 | MODIFIER_META | |
320 | 0 | MODIFIER_OS | |
321 | 0 | MODIFIER_SHIFT)); |
322 | 0 | } |
323 | | |
324 | | virtual WidgetEvent* Duplicate() const override |
325 | 0 | { |
326 | 0 | MOZ_ASSERT(mClass == eKeyboardEventClass, |
327 | 0 | "Duplicate() must be overridden by sub class"); |
328 | 0 | // Not copying widget, it is a weak reference. |
329 | 0 | WidgetKeyboardEvent* result = |
330 | 0 | new WidgetKeyboardEvent(false, mMessage, nullptr); |
331 | 0 | result->AssignKeyEventData(*this, true); |
332 | 0 | result->mEditCommandsForSingleLineEditor = mEditCommandsForSingleLineEditor; |
333 | 0 | result->mEditCommandsForMultiLineEditor = mEditCommandsForMultiLineEditor; |
334 | 0 | result->mEditCommandsForRichTextEditor = mEditCommandsForRichTextEditor; |
335 | 0 | result->mFlags = mFlags; |
336 | 0 | return result; |
337 | 0 | } |
338 | | |
339 | | // OS translated Unicode chars which are used for accesskey and accelkey |
340 | | // handling. The handlers will try from first character to last character. |
341 | | nsTArray<AlternativeCharCode> mAlternativeCharCodes; |
342 | | // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING. |
343 | | nsString mKeyValue; |
344 | | // DOM KeyboardEvent.code only when mCodeNameIndex is |
345 | | // CODE_NAME_INDEX_USE_STRING. |
346 | | nsString mCodeValue; |
347 | | |
348 | | #ifdef XP_MACOSX |
349 | | // Values given by a native NSEvent, for use with Cocoa NPAPI plugins. |
350 | | nsString mNativeCharacters; |
351 | | nsString mNativeCharactersIgnoringModifiers; |
352 | | // If this is non-empty, create a text event for plugins instead of a |
353 | | // keyboard event. |
354 | | nsString mPluginTextEventString; |
355 | | #endif // #ifdef XP_MACOSX |
356 | | |
357 | | // OS-specific native event can optionally be preserved |
358 | | void* mNativeKeyEvent; |
359 | | // A DOM keyCode value or 0. If a keypress event whose mCharCode is 0, this |
360 | | // should be 0. |
361 | | uint32_t mKeyCode; |
362 | | // If the instance is a keypress event of a printable key, this is a UTF-16 |
363 | | // value of the key. Otherwise, 0. This value must not be a control |
364 | | // character when some modifiers are active. Then, this value should be an |
365 | | // unmodified value except Shift and AltGr. |
366 | | uint32_t mCharCode; |
367 | | // mPseudoCharCode is valid only when mMessage is an eKeyDown event. |
368 | | // This stores mCharCode value of keypress event which is fired with same |
369 | | // key value and same modifier state. |
370 | | uint32_t mPseudoCharCode; |
371 | | // One of eKeyLocation* |
372 | | uint32_t mLocation; |
373 | | // Unique id associated with a keydown / keypress event. It's ok if this wraps |
374 | | // over long periods. |
375 | | uint32_t mUniqueId; |
376 | | |
377 | | #ifdef XP_MACOSX |
378 | | // Values given by a native NSEvent, for use with Cocoa NPAPI plugins. |
379 | | uint32_t mNativeModifierFlags; |
380 | | uint16_t mNativeKeyCode; |
381 | | #endif // #ifdef XP_MACOSX |
382 | | |
383 | | // DOM KeyboardEvent.key |
384 | | KeyNameIndex mKeyNameIndex; |
385 | | // DOM KeyboardEvent.code |
386 | | CodeNameIndex mCodeNameIndex; |
387 | | |
388 | | // Indicates whether the event is generated by auto repeat or not. |
389 | | // if this is keyup event, always false. |
390 | | bool mIsRepeat; |
391 | | // Indicates whether the event is generated during IME (or deadkey) |
392 | | // composition. This is initialized by EventStateManager. So, key event |
393 | | // dispatchers don't need to initialize this. |
394 | | bool mIsComposing; |
395 | | // Indicates whether the event is synthesized from Text Input Processor |
396 | | // or an actual event from nsAppShell. |
397 | | bool mIsSynthesizedByTIP; |
398 | | // Indicates whether the event is skippable in remote process. |
399 | | // Don't refer this member directly when you need to check this. |
400 | | // Use CanSkipInRemoteProcess() instead. |
401 | | bool mMaybeSkippableInRemoteProcess; |
402 | | |
403 | | bool CanSkipInRemoteProcess() const |
404 | 0 | { |
405 | 0 | // If this is a repeat event (i.e., generated by auto-repeat feature of |
406 | 0 | // the platform), remove process may skip to handle it because of |
407 | 0 | // performances reasons.. However, if it's caused by odd keyboard utils, |
408 | 0 | // we should not ignore any key events even marked as repeated since |
409 | 0 | // generated key sequence may be important to input proper text. E.g., |
410 | 0 | // "SinhalaTamil IME" on Windows emulates dead key like input with |
411 | 0 | // generating WM_KEYDOWN for VK_PACKET (inputting any Unicode characters |
412 | 0 | // without keyboard layout information) and VK_BACK (Backspace) to remove |
413 | 0 | // previous character(s) and those messages may be marked as "repeat" by |
414 | 0 | // their bug. |
415 | 0 | return mIsRepeat && mMaybeSkippableInRemoteProcess; |
416 | 0 | } |
417 | | |
418 | | /** |
419 | | * Retrieves all edit commands from mWidget. This shouldn't be called when |
420 | | * the instance is an untrusted event, doesn't have widget or in non-chrome |
421 | | * process. |
422 | | */ |
423 | | void InitAllEditCommands(); |
424 | | |
425 | | /** |
426 | | * Retrieves edit commands from mWidget only for aType. This shouldn't be |
427 | | * called when the instance is an untrusted event or doesn't have widget. |
428 | | */ |
429 | | void InitEditCommandsFor(nsIWidget::NativeKeyBindingsType aType); |
430 | | |
431 | | /** |
432 | | * PreventNativeKeyBindings() makes the instance to not cause any edit |
433 | | * actions even if it matches with a native key binding. |
434 | | */ |
435 | | void PreventNativeKeyBindings() |
436 | 0 | { |
437 | 0 | mEditCommandsForSingleLineEditor.Clear(); |
438 | 0 | mEditCommandsForMultiLineEditor.Clear(); |
439 | 0 | mEditCommandsForRichTextEditor.Clear(); |
440 | 0 | mEditCommandsForSingleLineEditorInitialized = true; |
441 | 0 | mEditCommandsForMultiLineEditorInitialized = true; |
442 | 0 | mEditCommandsForRichTextEditorInitialized = true; |
443 | 0 | } |
444 | | |
445 | | /** |
446 | | * EditCommandsConstRef() returns reference to edit commands for aType. |
447 | | */ |
448 | | const nsTArray<CommandInt>& |
449 | | EditCommandsConstRef(nsIWidget::NativeKeyBindingsType aType) const |
450 | 0 | { |
451 | 0 | return const_cast<WidgetKeyboardEvent*>(this)->EditCommandsRef(aType); |
452 | 0 | } |
453 | | |
454 | | /** |
455 | | * IsEditCommandsInitialized() returns true if edit commands for aType |
456 | | * was already initialized. Otherwise, false. |
457 | | */ |
458 | | bool IsEditCommandsInitialized( |
459 | | nsIWidget::NativeKeyBindingsType aType) const |
460 | 0 | { |
461 | 0 | return const_cast<WidgetKeyboardEvent*>(this)-> |
462 | 0 | IsEditCommandsInitializedRef(aType); |
463 | 0 | } |
464 | | |
465 | | #ifdef DEBUG |
466 | | /** |
467 | | * AreAllEditCommandsInitialized() returns true if edit commands for all |
468 | | * types were already initialized. Otherwise, false. |
469 | | */ |
470 | | bool AreAllEditCommandsInitialized() const |
471 | | { |
472 | | return mEditCommandsForSingleLineEditorInitialized && |
473 | | mEditCommandsForMultiLineEditorInitialized && |
474 | | mEditCommandsForRichTextEditorInitialized; |
475 | | } |
476 | | #endif // #ifdef DEBUG |
477 | | |
478 | | /** |
479 | | * Execute edit commands for aType. |
480 | | * |
481 | | * @return true if the caller should do nothing anymore. |
482 | | * false, otherwise. |
483 | | */ |
484 | | typedef void (*DoCommandCallback)(Command, void*); |
485 | | bool ExecuteEditCommands(nsIWidget::NativeKeyBindingsType aType, |
486 | | DoCommandCallback aCallback, |
487 | | void* aCallbackData); |
488 | | |
489 | | // If the key should cause keypress events, this returns true. |
490 | | // Otherwise, false. |
491 | | bool ShouldCauseKeypressEvents() const; |
492 | | |
493 | | // mCharCode value of non-eKeyPress events is always 0. However, if |
494 | | // non-eKeyPress event has one or more alternative char code values, |
495 | | // its first item should be the mCharCode value of following eKeyPress event. |
496 | | // PseudoCharCode() returns mCharCode value for eKeyPress event, |
497 | | // the first alternative char code value of non-eKeyPress event or 0. |
498 | | uint32_t PseudoCharCode() const |
499 | 0 | { |
500 | 0 | return mMessage == eKeyPress ? mCharCode : mPseudoCharCode; |
501 | 0 | } |
502 | | void SetCharCode(uint32_t aCharCode) |
503 | 0 | { |
504 | 0 | if (mMessage == eKeyPress) { |
505 | 0 | mCharCode = aCharCode; |
506 | 0 | } else { |
507 | 0 | mPseudoCharCode = aCharCode; |
508 | 0 | } |
509 | 0 | } |
510 | | |
511 | | void GetDOMKeyName(nsAString& aKeyName) |
512 | 0 | { |
513 | 0 | if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) { |
514 | 0 | aKeyName = mKeyValue; |
515 | 0 | return; |
516 | 0 | } |
517 | 0 | GetDOMKeyName(mKeyNameIndex, aKeyName); |
518 | 0 | } |
519 | | void GetDOMCodeName(nsAString& aCodeName) |
520 | 0 | { |
521 | 0 | if (mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) { |
522 | 0 | aCodeName = mCodeValue; |
523 | 0 | return; |
524 | 0 | } |
525 | 0 | GetDOMCodeName(mCodeNameIndex, aCodeName); |
526 | 0 | } |
527 | | |
528 | | /** |
529 | | * GetFallbackKeyCodeOfPunctuationKey() returns a DOM keyCode value for |
530 | | * aCodeNameIndex. This is keyCode value of the key when active keyboard |
531 | | * layout is ANSI (US), JIS or ABNT keyboard layout (the latter 2 layouts |
532 | | * are used only when ANSI doesn't have the key). The result is useful |
533 | | * if the key doesn't produce ASCII character with active keyboard layout |
534 | | * nor with alternative ASCII capable keyboard layout. |
535 | | */ |
536 | | static uint32_t |
537 | | GetFallbackKeyCodeOfPunctuationKey(CodeNameIndex aCodeNameIndex); |
538 | | |
539 | | bool IsModifierKeyEvent() const |
540 | 0 | { |
541 | 0 | return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE; |
542 | 0 | } |
543 | | |
544 | | /** |
545 | | * Get the candidates for shortcut key. |
546 | | * |
547 | | * @param aCandidates [out] the candidate shortcut key combination list. |
548 | | * the first item is most preferred. |
549 | | */ |
550 | | void GetShortcutKeyCandidates(ShortcutKeyCandidateArray& aCandidates) const; |
551 | | |
552 | | /** |
553 | | * Get the candidates for access key. |
554 | | * |
555 | | * @param aCandidates [out] the candidate access key list. |
556 | | * the first item is most preferred. |
557 | | */ |
558 | | void GetAccessKeyCandidates(nsTArray<uint32_t>& aCandidates) const; |
559 | | |
560 | | /** |
561 | | * Check whether the modifiers match with chrome access key or |
562 | | * content access key. |
563 | | */ |
564 | | bool ModifiersMatchWithAccessKey(AccessKeyType aType) const; |
565 | | |
566 | | /** |
567 | | * Return active modifiers which may match with access key. |
568 | | * For example, even if Alt is access key modifier, then, when Control, |
569 | | * CapseLock and NumLock are active, this returns only MODIFIER_CONTROL. |
570 | | */ |
571 | | Modifiers ModifiersForAccessKeyMatching() const; |
572 | | |
573 | | /** |
574 | | * Return access key modifiers. |
575 | | */ |
576 | | static Modifiers AccessKeyModifiers(AccessKeyType aType); |
577 | | |
578 | | static void Shutdown(); |
579 | | |
580 | | /** |
581 | | * ComputeLocationFromCodeValue() returns one of .mLocation value |
582 | | * (eKeyLocation*) which is the most preferred value for the specified code |
583 | | * value. |
584 | | */ |
585 | | static uint32_t ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex); |
586 | | |
587 | | /** |
588 | | * ComputeKeyCodeFromKeyNameIndex() return a .mKeyCode value which can be |
589 | | * mapped from the specified key value. Note that this returns 0 if the |
590 | | * key name index is KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING. |
591 | | * This means that this method is useful only for non-printable keys. |
592 | | */ |
593 | | static uint32_t ComputeKeyCodeFromKeyNameIndex(KeyNameIndex aKeyNameIndex); |
594 | | |
595 | | /** |
596 | | * GetModifierForKeyName() returns a value of Modifier which is activated |
597 | | * by the aKeyNameIndex. |
598 | | */ |
599 | | static Modifier GetModifierForKeyName(KeyNameIndex aKeyNameIndex); |
600 | | |
601 | | /** |
602 | | * IsLockableModifier() returns true if aKeyNameIndex is a lockable modifier |
603 | | * key such as CapsLock and NumLock. |
604 | | */ |
605 | | static bool IsLockableModifier(KeyNameIndex aKeyNameIndex); |
606 | | |
607 | | static void GetDOMKeyName(KeyNameIndex aKeyNameIndex, |
608 | | nsAString& aKeyName); |
609 | | static void GetDOMCodeName(CodeNameIndex aCodeNameIndex, |
610 | | nsAString& aCodeName); |
611 | | |
612 | | static KeyNameIndex GetKeyNameIndex(const nsAString& aKeyValue); |
613 | | static CodeNameIndex GetCodeNameIndex(const nsAString& aCodeValue); |
614 | | |
615 | | static const char* GetCommandStr(Command aCommand); |
616 | | |
617 | | void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets) |
618 | 0 | { |
619 | 0 | AssignInputEventData(aEvent, aCopyTargets); |
620 | 0 |
|
621 | 0 | mKeyCode = aEvent.mKeyCode; |
622 | 0 | mCharCode = aEvent.mCharCode; |
623 | 0 | mPseudoCharCode = aEvent.mPseudoCharCode; |
624 | 0 | mLocation = aEvent.mLocation; |
625 | 0 | mAlternativeCharCodes = aEvent.mAlternativeCharCodes; |
626 | 0 | mIsRepeat = aEvent.mIsRepeat; |
627 | 0 | mIsComposing = aEvent.mIsComposing; |
628 | 0 | mKeyNameIndex = aEvent.mKeyNameIndex; |
629 | 0 | mCodeNameIndex = aEvent.mCodeNameIndex; |
630 | 0 | mKeyValue = aEvent.mKeyValue; |
631 | 0 | mCodeValue = aEvent.mCodeValue; |
632 | 0 | // Don't copy mNativeKeyEvent because it may be referred after its instance |
633 | 0 | // is destroyed. |
634 | 0 | mNativeKeyEvent = nullptr; |
635 | 0 | mUniqueId = aEvent.mUniqueId; |
636 | | #ifdef XP_MACOSX |
637 | | mNativeKeyCode = aEvent.mNativeKeyCode; |
638 | | mNativeModifierFlags = aEvent.mNativeModifierFlags; |
639 | | mNativeCharacters.Assign(aEvent.mNativeCharacters); |
640 | | mNativeCharactersIgnoringModifiers. |
641 | | Assign(aEvent.mNativeCharactersIgnoringModifiers); |
642 | | mPluginTextEventString.Assign(aEvent.mPluginTextEventString); |
643 | | #endif |
644 | | mIsSynthesizedByTIP = aEvent.mIsSynthesizedByTIP; |
645 | 0 | mMaybeSkippableInRemoteProcess = aEvent.mMaybeSkippableInRemoteProcess; |
646 | 0 |
|
647 | 0 | // Don't copy mEditCommandsFor*Editor because it may require a lot of |
648 | 0 | // memory space. For example, if the event is dispatched but grabbed by |
649 | 0 | // a JS variable, they are not necessary anymore. |
650 | 0 |
|
651 | 0 | mEditCommandsForSingleLineEditorInitialized = |
652 | 0 | aEvent.mEditCommandsForSingleLineEditorInitialized; |
653 | 0 | mEditCommandsForMultiLineEditorInitialized = |
654 | 0 | aEvent.mEditCommandsForMultiLineEditorInitialized; |
655 | 0 | mEditCommandsForRichTextEditorInitialized = |
656 | 0 | aEvent.mEditCommandsForRichTextEditorInitialized; |
657 | 0 | } |
658 | | |
659 | | private: |
660 | | static const char16_t* const kKeyNames[]; |
661 | | static const char16_t* const kCodeNames[]; |
662 | | typedef nsDataHashtable<nsStringHashKey, |
663 | | KeyNameIndex> KeyNameIndexHashtable; |
664 | | typedef nsDataHashtable<nsStringHashKey, |
665 | | CodeNameIndex> CodeNameIndexHashtable; |
666 | | static KeyNameIndexHashtable* sKeyNameIndexHashtable; |
667 | | static CodeNameIndexHashtable* sCodeNameIndexHashtable; |
668 | | |
669 | | // mEditCommandsFor*Editor store edit commands. This should be initialized |
670 | | // with InitEditCommandsFor(). |
671 | | // XXX Ideally, this should be array of Command rather than CommandInt. |
672 | | // However, ParamTraits isn't aware of enum array. |
673 | | nsTArray<CommandInt> mEditCommandsForSingleLineEditor; |
674 | | nsTArray<CommandInt> mEditCommandsForMultiLineEditor; |
675 | | nsTArray<CommandInt> mEditCommandsForRichTextEditor; |
676 | | |
677 | | nsTArray<CommandInt>& EditCommandsRef(nsIWidget::NativeKeyBindingsType aType) |
678 | 0 | { |
679 | 0 | switch (aType) { |
680 | 0 | case nsIWidget::NativeKeyBindingsForSingleLineEditor: |
681 | 0 | return mEditCommandsForSingleLineEditor; |
682 | 0 | case nsIWidget::NativeKeyBindingsForMultiLineEditor: |
683 | 0 | return mEditCommandsForMultiLineEditor; |
684 | 0 | case nsIWidget::NativeKeyBindingsForRichTextEditor: |
685 | 0 | return mEditCommandsForRichTextEditor; |
686 | 0 | default: |
687 | 0 | MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE( |
688 | 0 | "Invalid native key binding type"); |
689 | 0 | } |
690 | 0 | } |
691 | | |
692 | | // mEditCommandsFor*EditorInitialized are set to true when |
693 | | // InitEditCommandsFor() initializes edit commands for the type. |
694 | | bool mEditCommandsForSingleLineEditorInitialized; |
695 | | bool mEditCommandsForMultiLineEditorInitialized; |
696 | | bool mEditCommandsForRichTextEditorInitialized; |
697 | | |
698 | | bool& IsEditCommandsInitializedRef(nsIWidget::NativeKeyBindingsType aType) |
699 | 0 | { |
700 | 0 | switch (aType) { |
701 | 0 | case nsIWidget::NativeKeyBindingsForSingleLineEditor: |
702 | 0 | return mEditCommandsForSingleLineEditorInitialized; |
703 | 0 | case nsIWidget::NativeKeyBindingsForMultiLineEditor: |
704 | 0 | return mEditCommandsForMultiLineEditorInitialized; |
705 | 0 | case nsIWidget::NativeKeyBindingsForRichTextEditor: |
706 | 0 | return mEditCommandsForRichTextEditorInitialized; |
707 | 0 | default: |
708 | 0 | MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE( |
709 | 0 | "Invalid native key binding type"); |
710 | 0 | } |
711 | 0 | } |
712 | | |
713 | | static int32_t GenericAccessModifierKeyPref(); |
714 | | static int32_t ChromeAccessModifierMaskPref(); |
715 | | static int32_t ContentAccessModifierMaskPref(); |
716 | | }; |
717 | | |
718 | | /****************************************************************************** |
719 | | * mozilla::WidgetCompositionEvent |
720 | | ******************************************************************************/ |
721 | | |
722 | | class WidgetCompositionEvent : public WidgetGUIEvent |
723 | | { |
724 | | private: |
725 | | friend class mozilla::dom::PBrowserParent; |
726 | | friend class mozilla::dom::PBrowserChild; |
727 | | |
728 | | WidgetCompositionEvent() |
729 | | : mOriginalMessage(eVoidEvent) |
730 | 0 | { |
731 | 0 | } |
732 | | |
733 | | public: |
734 | | virtual WidgetCompositionEvent* AsCompositionEvent() override |
735 | 0 | { |
736 | 0 | return this; |
737 | 0 | } |
738 | | |
739 | | WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage, |
740 | | nsIWidget* aWidget) |
741 | | : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass) |
742 | | , mNativeIMEContext(aWidget) |
743 | | , mOriginalMessage(eVoidEvent) |
744 | 0 | { |
745 | 0 | } |
746 | | |
747 | | virtual WidgetEvent* Duplicate() const override |
748 | 0 | { |
749 | 0 | MOZ_ASSERT(mClass == eCompositionEventClass, |
750 | 0 | "Duplicate() must be overridden by sub class"); |
751 | 0 | // Not copying widget, it is a weak reference. |
752 | 0 | WidgetCompositionEvent* result = |
753 | 0 | new WidgetCompositionEvent(false, mMessage, nullptr); |
754 | 0 | result->AssignCompositionEventData(*this, true); |
755 | 0 | result->mFlags = mFlags; |
756 | 0 | return result; |
757 | 0 | } |
758 | | |
759 | | // The composition string or the commit string. If the instance is a |
760 | | // compositionstart event, this is initialized with selected text by |
761 | | // TextComposition automatically. |
762 | | nsString mData; |
763 | | |
764 | | RefPtr<TextRangeArray> mRanges; |
765 | | |
766 | | // mNativeIMEContext stores the native IME context which causes the |
767 | | // composition event. |
768 | | widget::NativeIMEContext mNativeIMEContext; |
769 | | |
770 | | // If the instance is a clone of another event, mOriginalMessage stores |
771 | | // the another event's mMessage. |
772 | | EventMessage mOriginalMessage; |
773 | | |
774 | | void AssignCompositionEventData(const WidgetCompositionEvent& aEvent, |
775 | | bool aCopyTargets) |
776 | 0 | { |
777 | 0 | AssignGUIEventData(aEvent, aCopyTargets); |
778 | 0 |
|
779 | 0 | mData = aEvent.mData; |
780 | 0 | mOriginalMessage = aEvent.mOriginalMessage; |
781 | 0 | mRanges = aEvent.mRanges; |
782 | 0 |
|
783 | 0 | // Currently, we don't need to copy the other members because they are |
784 | 0 | // for internal use only (not available from JS). |
785 | 0 | } |
786 | | |
787 | | bool IsComposing() const |
788 | 0 | { |
789 | 0 | return mRanges && mRanges->IsComposing(); |
790 | 0 | } |
791 | | |
792 | | uint32_t TargetClauseOffset() const |
793 | 0 | { |
794 | 0 | return mRanges ? mRanges->TargetClauseOffset() : 0; |
795 | 0 | } |
796 | | |
797 | | uint32_t TargetClauseLength() const |
798 | 0 | { |
799 | 0 | uint32_t length = UINT32_MAX; |
800 | 0 | if (mRanges) { |
801 | 0 | length = mRanges->TargetClauseLength(); |
802 | 0 | } |
803 | 0 | return length == UINT32_MAX ? mData.Length() : length; |
804 | 0 | } |
805 | | |
806 | | uint32_t RangeCount() const |
807 | 0 | { |
808 | 0 | return mRanges ? mRanges->Length() : 0; |
809 | 0 | } |
810 | | |
811 | | bool CausesDOMTextEvent() const |
812 | 0 | { |
813 | 0 | return mMessage == eCompositionChange || |
814 | 0 | mMessage == eCompositionCommit || |
815 | 0 | mMessage == eCompositionCommitAsIs; |
816 | 0 | } |
817 | | |
818 | | bool CausesDOMCompositionEndEvent() const |
819 | 0 | { |
820 | 0 | return mMessage == eCompositionEnd || |
821 | 0 | mMessage == eCompositionCommit || |
822 | 0 | mMessage == eCompositionCommitAsIs; |
823 | 0 | } |
824 | | |
825 | | bool IsFollowedByCompositionEnd() const |
826 | 0 | { |
827 | 0 | return IsFollowedByCompositionEnd(mOriginalMessage); |
828 | 0 | } |
829 | | |
830 | | static bool IsFollowedByCompositionEnd(EventMessage aEventMessage) |
831 | 0 | { |
832 | 0 | return aEventMessage == eCompositionCommit || |
833 | 0 | aEventMessage == eCompositionCommitAsIs; |
834 | 0 | } |
835 | | }; |
836 | | |
837 | | /****************************************************************************** |
838 | | * mozilla::WidgetQueryContentEvent |
839 | | ******************************************************************************/ |
840 | | |
841 | | class WidgetQueryContentEvent : public WidgetGUIEvent |
842 | | { |
843 | | private: |
844 | | friend class dom::PBrowserParent; |
845 | | friend class dom::PBrowserChild; |
846 | | |
847 | | WidgetQueryContentEvent() |
848 | | : mSucceeded(false) |
849 | | , mUseNativeLineBreak(true) |
850 | | , mWithFontRanges(false) |
851 | 0 | { |
852 | 0 | MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments"); |
853 | 0 | } |
854 | | |
855 | | public: |
856 | | virtual WidgetQueryContentEvent* AsQueryContentEvent() override |
857 | 0 | { |
858 | 0 | return this; |
859 | 0 | } |
860 | | |
861 | | WidgetQueryContentEvent(bool aIsTrusted, EventMessage aMessage, |
862 | | nsIWidget* aWidget) |
863 | | : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eQueryContentEventClass) |
864 | | , mSucceeded(false) |
865 | | , mUseNativeLineBreak(true) |
866 | | , mWithFontRanges(false) |
867 | 0 | { |
868 | 0 | } |
869 | | |
870 | | WidgetQueryContentEvent(EventMessage aMessage, |
871 | | const WidgetQueryContentEvent& aOtherEvent) |
872 | | : WidgetGUIEvent(aOtherEvent.IsTrusted(), aMessage, |
873 | | const_cast<nsIWidget*>(aOtherEvent.mWidget.get()), |
874 | | eQueryContentEventClass) |
875 | | , mSucceeded(false) |
876 | | , mUseNativeLineBreak(aOtherEvent.mUseNativeLineBreak) |
877 | | , mWithFontRanges(false) |
878 | 0 | { |
879 | 0 | } |
880 | | |
881 | | virtual WidgetEvent* Duplicate() const override |
882 | 0 | { |
883 | 0 | // This event isn't an internal event of any DOM event. |
884 | 0 | NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), |
885 | 0 | "WidgetQueryContentEvent needs to support Duplicate()"); |
886 | 0 | MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()"); |
887 | 0 | } |
888 | | |
889 | | struct Options final |
890 | | { |
891 | | bool mUseNativeLineBreak; |
892 | | bool mRelativeToInsertionPoint; |
893 | | |
894 | | explicit Options() |
895 | | : mUseNativeLineBreak(true) |
896 | | , mRelativeToInsertionPoint(false) |
897 | 0 | { |
898 | 0 | } |
899 | | |
900 | | explicit Options(const WidgetQueryContentEvent& aEvent) |
901 | | : mUseNativeLineBreak(aEvent.mUseNativeLineBreak) |
902 | | , mRelativeToInsertionPoint(aEvent.mInput.mRelativeToInsertionPoint) |
903 | 0 | { |
904 | 0 | } |
905 | | }; |
906 | | |
907 | | void Init(const Options& aOptions) |
908 | 0 | { |
909 | 0 | mUseNativeLineBreak = aOptions.mUseNativeLineBreak; |
910 | 0 | mInput.mRelativeToInsertionPoint = aOptions.mRelativeToInsertionPoint; |
911 | 0 | MOZ_ASSERT(mInput.IsValidEventMessage(mMessage)); |
912 | 0 | } |
913 | | |
914 | | void InitForQueryTextContent(int64_t aOffset, uint32_t aLength, |
915 | | const Options& aOptions = Options()) |
916 | 0 | { |
917 | 0 | NS_ASSERTION(mMessage == eQueryTextContent, |
918 | 0 | "wrong initializer is called"); |
919 | 0 | mInput.mOffset = aOffset; |
920 | 0 | mInput.mLength = aLength; |
921 | 0 | Init(aOptions); |
922 | 0 | MOZ_ASSERT(mInput.IsValidOffset()); |
923 | 0 | } |
924 | | |
925 | | void InitForQueryCaretRect(int64_t aOffset, |
926 | | const Options& aOptions = Options()) |
927 | 0 | { |
928 | 0 | NS_ASSERTION(mMessage == eQueryCaretRect, |
929 | 0 | "wrong initializer is called"); |
930 | 0 | mInput.mOffset = aOffset; |
931 | 0 | Init(aOptions); |
932 | 0 | MOZ_ASSERT(mInput.IsValidOffset()); |
933 | 0 | } |
934 | | |
935 | | void InitForQueryTextRect(int64_t aOffset, uint32_t aLength, |
936 | | const Options& aOptions = Options()) |
937 | 0 | { |
938 | 0 | NS_ASSERTION(mMessage == eQueryTextRect, |
939 | 0 | "wrong initializer is called"); |
940 | 0 | mInput.mOffset = aOffset; |
941 | 0 | mInput.mLength = aLength; |
942 | 0 | Init(aOptions); |
943 | 0 | MOZ_ASSERT(mInput.IsValidOffset()); |
944 | 0 | } |
945 | | |
946 | | void InitForQuerySelectedText(SelectionType aSelectionType, |
947 | | const Options& aOptions = Options()) |
948 | 0 | { |
949 | 0 | MOZ_ASSERT(mMessage == eQuerySelectedText); |
950 | 0 | MOZ_ASSERT(aSelectionType != SelectionType::eNone); |
951 | 0 | mInput.mSelectionType = aSelectionType; |
952 | 0 | Init(aOptions); |
953 | 0 | } |
954 | | |
955 | | void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint) |
956 | 0 | { |
957 | 0 | NS_ASSERTION(mMessage == eQueryDOMWidgetHittest, |
958 | 0 | "wrong initializer is called"); |
959 | 0 | mRefPoint = aPoint; |
960 | 0 | } |
961 | | |
962 | | void InitForQueryTextRectArray(uint32_t aOffset, uint32_t aLength, |
963 | | const Options& aOptions = Options()) |
964 | 0 | { |
965 | 0 | NS_ASSERTION(mMessage == eQueryTextRectArray, |
966 | 0 | "wrong initializer is called"); |
967 | 0 | mInput.mOffset = aOffset; |
968 | 0 | mInput.mLength = aLength; |
969 | 0 | Init(aOptions); |
970 | 0 | } |
971 | | |
972 | | void RequestFontRanges() |
973 | 0 | { |
974 | 0 | NS_ASSERTION(mMessage == eQueryTextContent, |
975 | 0 | "not querying text content"); |
976 | 0 | mWithFontRanges = true; |
977 | 0 | } |
978 | | |
979 | | uint32_t GetSelectionStart(void) const |
980 | 0 | { |
981 | 0 | NS_ASSERTION(mMessage == eQuerySelectedText, |
982 | 0 | "not querying selection"); |
983 | 0 | return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0); |
984 | 0 | } |
985 | | |
986 | | uint32_t GetSelectionEnd(void) const |
987 | 0 | { |
988 | 0 | NS_ASSERTION(mMessage == eQuerySelectedText, |
989 | 0 | "not querying selection"); |
990 | 0 | return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length()); |
991 | 0 | } |
992 | | |
993 | | mozilla::WritingMode GetWritingMode(void) const |
994 | 0 | { |
995 | 0 | NS_ASSERTION(mMessage == eQuerySelectedText || |
996 | 0 | mMessage == eQueryCaretRect || |
997 | 0 | mMessage == eQueryTextRect, |
998 | 0 | "not querying selection or text rect"); |
999 | 0 | return mReply.mWritingMode; |
1000 | 0 | } |
1001 | | |
1002 | | bool mSucceeded; |
1003 | | bool mUseNativeLineBreak; |
1004 | | bool mWithFontRanges; |
1005 | | struct Input final |
1006 | | { |
1007 | | uint32_t EndOffset() const |
1008 | 0 | { |
1009 | 0 | CheckedInt<uint32_t> endOffset = |
1010 | 0 | CheckedInt<uint32_t>(mOffset) + mLength; |
1011 | 0 | return NS_WARN_IF(!endOffset.isValid()) ? UINT32_MAX : endOffset.value(); |
1012 | 0 | } |
1013 | | |
1014 | | int64_t mOffset; |
1015 | | uint32_t mLength; |
1016 | | SelectionType mSelectionType; |
1017 | | // If mOffset is true, mOffset is relative to the start offset of |
1018 | | // composition if there is, otherwise, the start of the first selection |
1019 | | // range. |
1020 | | bool mRelativeToInsertionPoint; |
1021 | | |
1022 | | Input() |
1023 | | : mOffset(0) |
1024 | | , mLength(0) |
1025 | | , mSelectionType(SelectionType::eNormal) |
1026 | | , mRelativeToInsertionPoint(false) |
1027 | 0 | { |
1028 | 0 | } |
1029 | | |
1030 | | bool IsValidOffset() const |
1031 | 0 | { |
1032 | 0 | return mRelativeToInsertionPoint || mOffset >= 0; |
1033 | 0 | } |
1034 | | bool IsValidEventMessage(EventMessage aEventMessage) const |
1035 | 0 | { |
1036 | 0 | if (!mRelativeToInsertionPoint) { |
1037 | 0 | return true; |
1038 | 0 | } |
1039 | 0 | switch (aEventMessage) { |
1040 | 0 | case eQueryTextContent: |
1041 | 0 | case eQueryCaretRect: |
1042 | 0 | case eQueryTextRect: |
1043 | 0 | return true; |
1044 | 0 | default: |
1045 | 0 | return false; |
1046 | 0 | } |
1047 | 0 | } |
1048 | | bool MakeOffsetAbsolute(uint32_t aInsertionPointOffset) |
1049 | 0 | { |
1050 | 0 | if (NS_WARN_IF(!mRelativeToInsertionPoint)) { |
1051 | 0 | return true; |
1052 | 0 | } |
1053 | 0 | mRelativeToInsertionPoint = false; |
1054 | 0 | // If mOffset + aInsertionPointOffset becomes negative value, |
1055 | 0 | // we should assume the absolute offset is 0. |
1056 | 0 | if (mOffset < 0 && -mOffset > aInsertionPointOffset) { |
1057 | 0 | mOffset = 0; |
1058 | 0 | return true; |
1059 | 0 | } |
1060 | 0 | // Otherwise, we don't allow too large offset. |
1061 | 0 | CheckedInt<uint32_t> absOffset = mOffset + aInsertionPointOffset; |
1062 | 0 | if (NS_WARN_IF(!absOffset.isValid())) { |
1063 | 0 | mOffset = UINT32_MAX; |
1064 | 0 | return false; |
1065 | 0 | } |
1066 | 0 | mOffset = absOffset.value(); |
1067 | 0 | return true; |
1068 | 0 | } |
1069 | | } mInput; |
1070 | | |
1071 | | struct Reply final |
1072 | | { |
1073 | | void* mContentsRoot; |
1074 | | uint32_t mOffset; |
1075 | | // mTentativeCaretOffset is used by only eQueryCharacterAtPoint. |
1076 | | // This is the offset where caret would be if user clicked at the mRefPoint. |
1077 | | uint32_t mTentativeCaretOffset; |
1078 | | nsString mString; |
1079 | | // mRect is used by eQueryTextRect, eQueryCaretRect, eQueryCharacterAtPoint |
1080 | | // and eQueryEditorRect. The coordinates is system coordinates relative to |
1081 | | // the top level widget of mFocusedWidget. E.g., if a <xul:panel> which |
1082 | | // is owned by a window has focused editor, the offset of mRect is relative |
1083 | | // to the owner window, not the <xul:panel>. |
1084 | | mozilla::LayoutDeviceIntRect mRect; |
1085 | | // The return widget has the caret. This is set at all query events. |
1086 | | nsIWidget* mFocusedWidget; |
1087 | | // mozilla::WritingMode value at the end (focus) of the selection |
1088 | | mozilla::WritingMode mWritingMode; |
1089 | | // Used by eQuerySelectionAsTransferable |
1090 | | nsCOMPtr<nsITransferable> mTransferable; |
1091 | | // Used by eQueryTextContent with font ranges requested |
1092 | | AutoTArray<mozilla::FontRange, 1> mFontRanges; |
1093 | | // Used by eQueryTextRectArray |
1094 | | nsTArray<mozilla::LayoutDeviceIntRect> mRectArray; |
1095 | | // true if selection is reversed (end < start) |
1096 | | bool mReversed; |
1097 | | // true if the selection exists |
1098 | | bool mHasSelection; |
1099 | | // true if DOM element under mouse belongs to widget |
1100 | | bool mWidgetIsHit; |
1101 | | |
1102 | | Reply() |
1103 | | : mContentsRoot(nullptr) |
1104 | | , mOffset(NOT_FOUND) |
1105 | | , mTentativeCaretOffset(NOT_FOUND) |
1106 | | , mFocusedWidget(nullptr) |
1107 | | , mReversed(false) |
1108 | | , mHasSelection(false) |
1109 | | , mWidgetIsHit(false) |
1110 | 0 | { |
1111 | 0 | } |
1112 | | } mReply; |
1113 | | |
1114 | | enum |
1115 | | { |
1116 | | NOT_FOUND = UINT32_MAX |
1117 | | }; |
1118 | | |
1119 | | // values of mComputedScrollAction |
1120 | | enum |
1121 | | { |
1122 | | SCROLL_ACTION_NONE, |
1123 | | SCROLL_ACTION_LINE, |
1124 | | SCROLL_ACTION_PAGE |
1125 | | }; |
1126 | | }; |
1127 | | |
1128 | | /****************************************************************************** |
1129 | | * mozilla::WidgetSelectionEvent |
1130 | | ******************************************************************************/ |
1131 | | |
1132 | | class WidgetSelectionEvent : public WidgetGUIEvent |
1133 | | { |
1134 | | private: |
1135 | | friend class mozilla::dom::PBrowserParent; |
1136 | | friend class mozilla::dom::PBrowserChild; |
1137 | | |
1138 | | WidgetSelectionEvent() |
1139 | | : mOffset(0) |
1140 | | , mLength(0) |
1141 | | , mReversed(false) |
1142 | | , mExpandToClusterBoundary(true) |
1143 | | , mSucceeded(false) |
1144 | | , mUseNativeLineBreak(true) |
1145 | | , mReason(nsISelectionListener::NO_REASON) |
1146 | 0 | { |
1147 | 0 | } |
1148 | | |
1149 | | public: |
1150 | | virtual WidgetSelectionEvent* AsSelectionEvent() override |
1151 | 0 | { |
1152 | 0 | return this; |
1153 | 0 | } |
1154 | | |
1155 | | WidgetSelectionEvent(bool aIsTrusted, EventMessage aMessage, |
1156 | | nsIWidget* aWidget) |
1157 | | : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eSelectionEventClass) |
1158 | | , mOffset(0) |
1159 | | , mLength(0) |
1160 | | , mReversed(false) |
1161 | | , mExpandToClusterBoundary(true) |
1162 | | , mSucceeded(false) |
1163 | | , mUseNativeLineBreak(true) |
1164 | | , mReason(nsISelectionListener::NO_REASON) |
1165 | 0 | { |
1166 | 0 | } |
1167 | | |
1168 | | virtual WidgetEvent* Duplicate() const override |
1169 | 0 | { |
1170 | 0 | // This event isn't an internal event of any DOM event. |
1171 | 0 | NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), |
1172 | 0 | "WidgetSelectionEvent needs to support Duplicate()"); |
1173 | 0 | MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()"); |
1174 | 0 | return nullptr; |
1175 | 0 | } |
1176 | | |
1177 | | // Start offset of selection |
1178 | | uint32_t mOffset; |
1179 | | // Length of selection |
1180 | | uint32_t mLength; |
1181 | | // Selection "anchor" should be in front |
1182 | | bool mReversed; |
1183 | | // Cluster-based or character-based |
1184 | | bool mExpandToClusterBoundary; |
1185 | | // true if setting selection succeeded. |
1186 | | bool mSucceeded; |
1187 | | // true if native line breaks are used for mOffset and mLength |
1188 | | bool mUseNativeLineBreak; |
1189 | | // Fennec provides eSetSelection reason codes for downstream |
1190 | | // use in AccessibleCaret visibility logic. |
1191 | | int16_t mReason; |
1192 | | }; |
1193 | | |
1194 | | /****************************************************************************** |
1195 | | * mozilla::InternalEditorInputEvent |
1196 | | ******************************************************************************/ |
1197 | | |
1198 | | class InternalEditorInputEvent : public InternalUIEvent |
1199 | | { |
1200 | | private: |
1201 | | InternalEditorInputEvent() |
1202 | | : mIsComposing(false) |
1203 | 0 | { |
1204 | 0 | } |
1205 | | |
1206 | | public: |
1207 | | virtual InternalEditorInputEvent* AsEditorInputEvent() override |
1208 | 0 | { |
1209 | 0 | return this; |
1210 | 0 | } |
1211 | | |
1212 | | InternalEditorInputEvent(bool aIsTrusted, EventMessage aMessage, |
1213 | | nsIWidget* aWidget = nullptr) |
1214 | | : InternalUIEvent(aIsTrusted, aMessage, aWidget, eEditorInputEventClass) |
1215 | | , mIsComposing(false) |
1216 | 0 | { |
1217 | 0 | } |
1218 | | |
1219 | | virtual WidgetEvent* Duplicate() const override |
1220 | 0 | { |
1221 | 0 | MOZ_ASSERT(mClass == eEditorInputEventClass, |
1222 | 0 | "Duplicate() must be overridden by sub class"); |
1223 | 0 | // Not copying widget, it is a weak reference. |
1224 | 0 | InternalEditorInputEvent* result = |
1225 | 0 | new InternalEditorInputEvent(false, mMessage, nullptr); |
1226 | 0 | result->AssignEditorInputEventData(*this, true); |
1227 | 0 | result->mFlags = mFlags; |
1228 | 0 | return result; |
1229 | 0 | } |
1230 | | |
1231 | | bool mIsComposing; |
1232 | | |
1233 | | void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent, |
1234 | | bool aCopyTargets) |
1235 | 0 | { |
1236 | 0 | AssignUIEventData(aEvent, aCopyTargets); |
1237 | 0 |
|
1238 | 0 | mIsComposing = aEvent.mIsComposing; |
1239 | 0 | } |
1240 | | }; |
1241 | | |
1242 | | } // namespace mozilla |
1243 | | |
1244 | | #endif // mozilla_TextEvents_h__ |