|
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/EventForwards.h" // for KeyNameIndex, temporarily |
|
14 #include "mozilla/TextRange.h" |
|
15 #include "nsCOMPtr.h" |
|
16 #include "nsIDOMKeyEvent.h" |
|
17 #include "nsITransferable.h" |
|
18 #include "nsRect.h" |
|
19 #include "nsStringGlue.h" |
|
20 #include "nsTArray.h" |
|
21 |
|
22 /****************************************************************************** |
|
23 * virtual keycode values |
|
24 ******************************************************************************/ |
|
25 |
|
26 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode |
|
27 |
|
28 enum |
|
29 { |
|
30 #include "mozilla/VirtualKeyCodeList.h" |
|
31 }; |
|
32 |
|
33 #undef NS_DEFINE_VK |
|
34 |
|
35 #define kLatestSeqno UINT32_MAX |
|
36 |
|
37 namespace mozilla { |
|
38 |
|
39 namespace dom { |
|
40 class PBrowserParent; |
|
41 class PBrowserChild; |
|
42 } // namespace dom |
|
43 namespace plugins { |
|
44 class PPluginInstanceChild; |
|
45 } // namespace plugins |
|
46 |
|
47 /****************************************************************************** |
|
48 * mozilla::AlternativeCharCode |
|
49 * |
|
50 * This stores alternative charCode values of a key event with some modifiers. |
|
51 * The stored values proper for testing shortcut key or access key. |
|
52 ******************************************************************************/ |
|
53 |
|
54 struct AlternativeCharCode |
|
55 { |
|
56 AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode) : |
|
57 mUnshiftedCharCode(aUnshiftedCharCode), mShiftedCharCode(aShiftedCharCode) |
|
58 { |
|
59 } |
|
60 uint32_t mUnshiftedCharCode; |
|
61 uint32_t mShiftedCharCode; |
|
62 }; |
|
63 |
|
64 /****************************************************************************** |
|
65 * mozilla::WidgetKeyboardEvent |
|
66 ******************************************************************************/ |
|
67 |
|
68 class WidgetKeyboardEvent : public WidgetInputEvent |
|
69 { |
|
70 private: |
|
71 friend class dom::PBrowserParent; |
|
72 friend class dom::PBrowserChild; |
|
73 |
|
74 WidgetKeyboardEvent() |
|
75 { |
|
76 } |
|
77 |
|
78 public: |
|
79 virtual WidgetKeyboardEvent* AsKeyboardEvent() MOZ_OVERRIDE { return this; } |
|
80 |
|
81 WidgetKeyboardEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) |
|
82 : WidgetInputEvent(aIsTrusted, aMessage, aWidget, NS_KEY_EVENT) |
|
83 , keyCode(0) |
|
84 , charCode(0) |
|
85 , location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD) |
|
86 , isChar(false) |
|
87 , mIsRepeat(false) |
|
88 , mIsComposing(false) |
|
89 , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified) |
|
90 , mNativeKeyEvent(nullptr) |
|
91 , mUniqueId(0) |
|
92 { |
|
93 } |
|
94 |
|
95 virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE |
|
96 { |
|
97 MOZ_ASSERT(eventStructType == NS_KEY_EVENT, |
|
98 "Duplicate() must be overridden by sub class"); |
|
99 // Not copying widget, it is a weak reference. |
|
100 WidgetKeyboardEvent* result = |
|
101 new WidgetKeyboardEvent(false, message, nullptr); |
|
102 result->AssignKeyEventData(*this, true); |
|
103 result->mFlags = mFlags; |
|
104 return result; |
|
105 } |
|
106 |
|
107 // A DOM keyCode value or 0. If a keypress event whose charCode is 0, this |
|
108 // should be 0. |
|
109 uint32_t keyCode; |
|
110 // If the instance is a keypress event of a printable key, this is a UTF-16 |
|
111 // value of the key. Otherwise, 0. This value must not be a control |
|
112 // character when some modifiers are active. Then, this value should be an |
|
113 // unmodified value except Shift and AltGr. |
|
114 uint32_t charCode; |
|
115 // One of nsIDOMKeyEvent::DOM_KEY_LOCATION_* |
|
116 uint32_t location; |
|
117 // OS translated Unicode chars which are used for accesskey and accelkey |
|
118 // handling. The handlers will try from first character to last character. |
|
119 nsTArray<AlternativeCharCode> alternativeCharCodes; |
|
120 // Indicates whether the event signifies a printable character |
|
121 bool isChar; |
|
122 // Indicates whether the event is generated by auto repeat or not. |
|
123 // if this is keyup event, always false. |
|
124 bool mIsRepeat; |
|
125 // Indicates whether the event is generated during IME (or deadkey) |
|
126 // composition. This is initialized by EventStateManager. So, key event |
|
127 // dispatchers don't need to initialize this. |
|
128 bool mIsComposing; |
|
129 // DOM KeyboardEvent.key |
|
130 KeyNameIndex mKeyNameIndex; |
|
131 // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING. |
|
132 nsString mKeyValue; |
|
133 // OS-specific native event can optionally be preserved |
|
134 void* mNativeKeyEvent; |
|
135 // Unique id associated with a keydown / keypress event. Used in identifing |
|
136 // keypress events for removal from async event dispatch queue in metrofx |
|
137 // after preventDefault is called on keydown events. It's ok if this wraps |
|
138 // over long periods. |
|
139 uint32_t mUniqueId; |
|
140 |
|
141 void GetDOMKeyName(nsAString& aKeyName) |
|
142 { |
|
143 if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) { |
|
144 aKeyName = mKeyValue; |
|
145 return; |
|
146 } |
|
147 GetDOMKeyName(mKeyNameIndex, aKeyName); |
|
148 } |
|
149 |
|
150 static void GetDOMKeyName(mozilla::KeyNameIndex aKeyNameIndex, |
|
151 nsAString& aKeyName); |
|
152 |
|
153 static const char* GetCommandStr(Command aCommand); |
|
154 |
|
155 void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets) |
|
156 { |
|
157 AssignInputEventData(aEvent, aCopyTargets); |
|
158 |
|
159 keyCode = aEvent.keyCode; |
|
160 charCode = aEvent.charCode; |
|
161 location = aEvent.location; |
|
162 alternativeCharCodes = aEvent.alternativeCharCodes; |
|
163 isChar = aEvent.isChar; |
|
164 mIsRepeat = aEvent.mIsRepeat; |
|
165 mIsComposing = aEvent.mIsComposing; |
|
166 mKeyNameIndex = aEvent.mKeyNameIndex; |
|
167 mKeyValue = aEvent.mKeyValue; |
|
168 // Don't copy mNativeKeyEvent because it may be referred after its instance |
|
169 // is destroyed. |
|
170 mNativeKeyEvent = nullptr; |
|
171 mUniqueId = aEvent.mUniqueId; |
|
172 } |
|
173 }; |
|
174 |
|
175 /****************************************************************************** |
|
176 * mozilla::WidgetTextEvent |
|
177 * |
|
178 * XXX WidgetTextEvent is fired with compositionupdate event almost every time. |
|
179 * This wastes performance and the cost of mantaining each platform's |
|
180 * implementation. Therefore, we should merge WidgetTextEvent and |
|
181 * WidgetCompositionEvent. Then, DOM compositionupdate should be fired |
|
182 * from TextComposition automatically. |
|
183 ******************************************************************************/ |
|
184 |
|
185 class WidgetTextEvent : public WidgetGUIEvent |
|
186 { |
|
187 private: |
|
188 friend class dom::PBrowserParent; |
|
189 friend class dom::PBrowserChild; |
|
190 friend class plugins::PPluginInstanceChild; |
|
191 |
|
192 WidgetTextEvent() |
|
193 : mSeqno(kLatestSeqno) |
|
194 , isChar(false) |
|
195 { |
|
196 } |
|
197 |
|
198 public: |
|
199 uint32_t mSeqno; |
|
200 |
|
201 public: |
|
202 virtual WidgetTextEvent* AsTextEvent() MOZ_OVERRIDE { return this; } |
|
203 |
|
204 WidgetTextEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) |
|
205 : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_TEXT_EVENT) |
|
206 , mSeqno(kLatestSeqno) |
|
207 , isChar(false) |
|
208 { |
|
209 } |
|
210 |
|
211 virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE |
|
212 { |
|
213 MOZ_ASSERT(eventStructType == NS_TEXT_EVENT, |
|
214 "Duplicate() must be overridden by sub class"); |
|
215 // Not copying widget, it is a weak reference. |
|
216 WidgetTextEvent* result = new WidgetTextEvent(false, message, nullptr); |
|
217 result->AssignTextEventData(*this, true); |
|
218 result->mFlags = mFlags; |
|
219 return result; |
|
220 } |
|
221 |
|
222 // The composition string or the commit string. |
|
223 nsString theText; |
|
224 // Indicates whether the event signifies printable text. |
|
225 // XXX This is not a standard, and most platforms don't set this properly. |
|
226 // So, perhaps, we can get rid of this. |
|
227 bool isChar; |
|
228 |
|
229 nsRefPtr<TextRangeArray> mRanges; |
|
230 |
|
231 void AssignTextEventData(const WidgetTextEvent& aEvent, bool aCopyTargets) |
|
232 { |
|
233 AssignGUIEventData(aEvent, aCopyTargets); |
|
234 |
|
235 isChar = aEvent.isChar; |
|
236 |
|
237 // Currently, we don't need to copy the other members because they are |
|
238 // for internal use only (not available from JS). |
|
239 } |
|
240 |
|
241 bool IsComposing() const |
|
242 { |
|
243 return mRanges && mRanges->IsComposing(); |
|
244 } |
|
245 |
|
246 uint32_t TargetClauseOffset() const |
|
247 { |
|
248 return mRanges ? mRanges->TargetClauseOffset() : 0; |
|
249 } |
|
250 |
|
251 uint32_t RangeCount() const |
|
252 { |
|
253 return mRanges ? mRanges->Length() : 0; |
|
254 } |
|
255 }; |
|
256 |
|
257 /****************************************************************************** |
|
258 * mozilla::WidgetCompositionEvent |
|
259 ******************************************************************************/ |
|
260 |
|
261 class WidgetCompositionEvent : public WidgetGUIEvent |
|
262 { |
|
263 private: |
|
264 friend class mozilla::dom::PBrowserParent; |
|
265 friend class mozilla::dom::PBrowserChild; |
|
266 |
|
267 WidgetCompositionEvent() |
|
268 : mSeqno(kLatestSeqno) |
|
269 { |
|
270 } |
|
271 |
|
272 public: |
|
273 uint32_t mSeqno; |
|
274 |
|
275 public: |
|
276 virtual WidgetCompositionEvent* AsCompositionEvent() MOZ_OVERRIDE |
|
277 { |
|
278 return this; |
|
279 } |
|
280 |
|
281 WidgetCompositionEvent(bool aIsTrusted, uint32_t aMessage, |
|
282 nsIWidget* aWidget) |
|
283 : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_COMPOSITION_EVENT) |
|
284 , mSeqno(kLatestSeqno) |
|
285 { |
|
286 // XXX compositionstart is cancelable in draft of DOM3 Events. |
|
287 // However, it doesn't make sense for us, we cannot cancel composition |
|
288 // when we send compositionstart event. |
|
289 mFlags.mCancelable = false; |
|
290 } |
|
291 |
|
292 virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE |
|
293 { |
|
294 MOZ_ASSERT(eventStructType == NS_COMPOSITION_EVENT, |
|
295 "Duplicate() must be overridden by sub class"); |
|
296 // Not copying widget, it is a weak reference. |
|
297 WidgetCompositionEvent* result = |
|
298 new WidgetCompositionEvent(false, message, nullptr); |
|
299 result->AssignCompositionEventData(*this, true); |
|
300 result->mFlags = mFlags; |
|
301 return result; |
|
302 } |
|
303 |
|
304 // The composition string or the commit string. If the instance is a |
|
305 // compositionstart event, this is initialized with selected text by |
|
306 // TextComposition automatically. |
|
307 nsString data; |
|
308 |
|
309 void AssignCompositionEventData(const WidgetCompositionEvent& aEvent, |
|
310 bool aCopyTargets) |
|
311 { |
|
312 AssignGUIEventData(aEvent, aCopyTargets); |
|
313 |
|
314 data = aEvent.data; |
|
315 } |
|
316 }; |
|
317 |
|
318 /****************************************************************************** |
|
319 * mozilla::WidgetQueryContentEvent |
|
320 ******************************************************************************/ |
|
321 |
|
322 class WidgetQueryContentEvent : public WidgetGUIEvent |
|
323 { |
|
324 private: |
|
325 friend class dom::PBrowserParent; |
|
326 friend class dom::PBrowserChild; |
|
327 |
|
328 WidgetQueryContentEvent() |
|
329 { |
|
330 MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments"); |
|
331 } |
|
332 |
|
333 public: |
|
334 virtual WidgetQueryContentEvent* AsQueryContentEvent() MOZ_OVERRIDE |
|
335 { |
|
336 return this; |
|
337 } |
|
338 |
|
339 WidgetQueryContentEvent(bool aIsTrusted, uint32_t aMessage, |
|
340 nsIWidget* aWidget) |
|
341 : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_QUERY_CONTENT_EVENT) |
|
342 , mSucceeded(false) |
|
343 , mWasAsync(false) |
|
344 , mUseNativeLineBreak(true) |
|
345 { |
|
346 } |
|
347 |
|
348 virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE |
|
349 { |
|
350 // This event isn't an internal event of any DOM event. |
|
351 NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), |
|
352 "WidgetQueryContentEvent needs to support Duplicate()"); |
|
353 MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()"); |
|
354 return nullptr; |
|
355 } |
|
356 |
|
357 void InitForQueryTextContent(uint32_t aOffset, uint32_t aLength, |
|
358 bool aUseNativeLineBreak = true) |
|
359 { |
|
360 NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT, |
|
361 "wrong initializer is called"); |
|
362 mInput.mOffset = aOffset; |
|
363 mInput.mLength = aLength; |
|
364 mUseNativeLineBreak = aUseNativeLineBreak; |
|
365 } |
|
366 |
|
367 void InitForQueryCaretRect(uint32_t aOffset, |
|
368 bool aUseNativeLineBreak = true) |
|
369 { |
|
370 NS_ASSERTION(message == NS_QUERY_CARET_RECT, |
|
371 "wrong initializer is called"); |
|
372 mInput.mOffset = aOffset; |
|
373 mUseNativeLineBreak = aUseNativeLineBreak; |
|
374 } |
|
375 |
|
376 void InitForQueryTextRect(uint32_t aOffset, uint32_t aLength, |
|
377 bool aUseNativeLineBreak = true) |
|
378 { |
|
379 NS_ASSERTION(message == NS_QUERY_TEXT_RECT, |
|
380 "wrong initializer is called"); |
|
381 mInput.mOffset = aOffset; |
|
382 mInput.mLength = aLength; |
|
383 mUseNativeLineBreak = aUseNativeLineBreak; |
|
384 } |
|
385 |
|
386 void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint) |
|
387 { |
|
388 NS_ASSERTION(message == NS_QUERY_DOM_WIDGET_HITTEST, |
|
389 "wrong initializer is called"); |
|
390 refPoint = aPoint; |
|
391 } |
|
392 |
|
393 uint32_t GetSelectionStart(void) const |
|
394 { |
|
395 NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, |
|
396 "not querying selection"); |
|
397 return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0); |
|
398 } |
|
399 |
|
400 uint32_t GetSelectionEnd(void) const |
|
401 { |
|
402 NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, |
|
403 "not querying selection"); |
|
404 return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length()); |
|
405 } |
|
406 |
|
407 bool mSucceeded; |
|
408 bool mWasAsync; |
|
409 bool mUseNativeLineBreak; |
|
410 struct |
|
411 { |
|
412 uint32_t mOffset; |
|
413 uint32_t mLength; |
|
414 } mInput; |
|
415 struct |
|
416 { |
|
417 void* mContentsRoot; |
|
418 uint32_t mOffset; |
|
419 nsString mString; |
|
420 // Finally, the coordinates is system coordinates. |
|
421 nsIntRect mRect; |
|
422 // The return widget has the caret. This is set at all query events. |
|
423 nsIWidget* mFocusedWidget; |
|
424 // true if selection is reversed (end < start) |
|
425 bool mReversed; |
|
426 // true if the selection exists |
|
427 bool mHasSelection; |
|
428 // true if DOM element under mouse belongs to widget |
|
429 bool mWidgetIsHit; |
|
430 // used by NS_QUERY_SELECTION_AS_TRANSFERABLE |
|
431 nsCOMPtr<nsITransferable> mTransferable; |
|
432 } mReply; |
|
433 |
|
434 enum |
|
435 { |
|
436 NOT_FOUND = UINT32_MAX |
|
437 }; |
|
438 |
|
439 // values of mComputedScrollAction |
|
440 enum |
|
441 { |
|
442 SCROLL_ACTION_NONE, |
|
443 SCROLL_ACTION_LINE, |
|
444 SCROLL_ACTION_PAGE |
|
445 }; |
|
446 }; |
|
447 |
|
448 /****************************************************************************** |
|
449 * mozilla::WidgetSelectionEvent |
|
450 ******************************************************************************/ |
|
451 |
|
452 class WidgetSelectionEvent : public WidgetGUIEvent |
|
453 { |
|
454 private: |
|
455 friend class mozilla::dom::PBrowserParent; |
|
456 friend class mozilla::dom::PBrowserChild; |
|
457 |
|
458 WidgetSelectionEvent() |
|
459 : mSeqno(kLatestSeqno) |
|
460 , mOffset(0) |
|
461 , mLength(0) |
|
462 , mReversed(false) |
|
463 , mExpandToClusterBoundary(true) |
|
464 , mSucceeded(false) |
|
465 { |
|
466 } |
|
467 |
|
468 public: |
|
469 uint32_t mSeqno; |
|
470 |
|
471 public: |
|
472 virtual WidgetSelectionEvent* AsSelectionEvent() MOZ_OVERRIDE |
|
473 { |
|
474 return this; |
|
475 } |
|
476 |
|
477 WidgetSelectionEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) |
|
478 : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_SELECTION_EVENT) |
|
479 , mSeqno(kLatestSeqno) |
|
480 , mOffset(0) |
|
481 , mLength(0) |
|
482 , mReversed(false) |
|
483 , mExpandToClusterBoundary(true) |
|
484 , mSucceeded(false) |
|
485 , mUseNativeLineBreak(true) |
|
486 { |
|
487 } |
|
488 |
|
489 virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE |
|
490 { |
|
491 // This event isn't an internal event of any DOM event. |
|
492 NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), |
|
493 "WidgetSelectionEvent needs to support Duplicate()"); |
|
494 MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()"); |
|
495 return nullptr; |
|
496 } |
|
497 |
|
498 // Start offset of selection |
|
499 uint32_t mOffset; |
|
500 // Length of selection |
|
501 uint32_t mLength; |
|
502 // Selection "anchor" should be in front |
|
503 bool mReversed; |
|
504 // Cluster-based or character-based |
|
505 bool mExpandToClusterBoundary; |
|
506 // true if setting selection succeeded. |
|
507 bool mSucceeded; |
|
508 // true if native line breaks are used for mOffset and mLength |
|
509 bool mUseNativeLineBreak; |
|
510 }; |
|
511 |
|
512 /****************************************************************************** |
|
513 * mozilla::InternalEditorInputEvent |
|
514 ******************************************************************************/ |
|
515 |
|
516 class InternalEditorInputEvent : public InternalUIEvent |
|
517 { |
|
518 private: |
|
519 InternalEditorInputEvent() |
|
520 : mIsComposing(false) |
|
521 { |
|
522 } |
|
523 |
|
524 public: |
|
525 virtual InternalEditorInputEvent* AsEditorInputEvent() MOZ_OVERRIDE |
|
526 { |
|
527 return this; |
|
528 } |
|
529 |
|
530 InternalEditorInputEvent(bool aIsTrusted, uint32_t aMessage, |
|
531 nsIWidget* aWidget) |
|
532 : InternalUIEvent(aIsTrusted, aMessage, aWidget, NS_EDITOR_INPUT_EVENT) |
|
533 , mIsComposing(false) |
|
534 { |
|
535 if (!aIsTrusted) { |
|
536 mFlags.mBubbles = false; |
|
537 mFlags.mCancelable = false; |
|
538 return; |
|
539 } |
|
540 |
|
541 mFlags.mBubbles = true; |
|
542 mFlags.mCancelable = false; |
|
543 } |
|
544 |
|
545 virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE |
|
546 { |
|
547 MOZ_ASSERT(eventStructType == NS_EDITOR_INPUT_EVENT, |
|
548 "Duplicate() must be overridden by sub class"); |
|
549 // Not copying widget, it is a weak reference. |
|
550 InternalEditorInputEvent* result = |
|
551 new InternalEditorInputEvent(false, message, nullptr); |
|
552 result->AssignEditorInputEventData(*this, true); |
|
553 result->mFlags = mFlags; |
|
554 return result; |
|
555 } |
|
556 |
|
557 bool mIsComposing; |
|
558 |
|
559 void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent, |
|
560 bool aCopyTargets) |
|
561 { |
|
562 AssignUIEventData(aEvent, aCopyTargets); |
|
563 |
|
564 mIsComposing = aEvent.mIsComposing; |
|
565 } |
|
566 }; |
|
567 |
|
568 } // namespace mozilla |
|
569 |
|
570 #endif // mozilla_TextEvents_h__ |