Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
6 #ifndef mozilla_TextEvents_h__
7 #define mozilla_TextEvents_h__
9 #include <stdint.h>
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"
22 /******************************************************************************
23 * virtual keycode values
24 ******************************************************************************/
26 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode
28 enum
29 {
30 #include "mozilla/VirtualKeyCodeList.h"
31 };
33 #undef NS_DEFINE_VK
35 #define kLatestSeqno UINT32_MAX
37 namespace mozilla {
39 namespace dom {
40 class PBrowserParent;
41 class PBrowserChild;
42 } // namespace dom
43 namespace plugins {
44 class PPluginInstanceChild;
45 } // namespace plugins
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 ******************************************************************************/
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 };
64 /******************************************************************************
65 * mozilla::WidgetKeyboardEvent
66 ******************************************************************************/
68 class WidgetKeyboardEvent : public WidgetInputEvent
69 {
70 private:
71 friend class dom::PBrowserParent;
72 friend class dom::PBrowserChild;
74 WidgetKeyboardEvent()
75 {
76 }
78 public:
79 virtual WidgetKeyboardEvent* AsKeyboardEvent() MOZ_OVERRIDE { return this; }
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 }
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 }
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;
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 }
150 static void GetDOMKeyName(mozilla::KeyNameIndex aKeyNameIndex,
151 nsAString& aKeyName);
153 static const char* GetCommandStr(Command aCommand);
155 void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets)
156 {
157 AssignInputEventData(aEvent, aCopyTargets);
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 };
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 ******************************************************************************/
185 class WidgetTextEvent : public WidgetGUIEvent
186 {
187 private:
188 friend class dom::PBrowserParent;
189 friend class dom::PBrowserChild;
190 friend class plugins::PPluginInstanceChild;
192 WidgetTextEvent()
193 : mSeqno(kLatestSeqno)
194 , isChar(false)
195 {
196 }
198 public:
199 uint32_t mSeqno;
201 public:
202 virtual WidgetTextEvent* AsTextEvent() MOZ_OVERRIDE { return this; }
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 }
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 }
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;
229 nsRefPtr<TextRangeArray> mRanges;
231 void AssignTextEventData(const WidgetTextEvent& aEvent, bool aCopyTargets)
232 {
233 AssignGUIEventData(aEvent, aCopyTargets);
235 isChar = aEvent.isChar;
237 // Currently, we don't need to copy the other members because they are
238 // for internal use only (not available from JS).
239 }
241 bool IsComposing() const
242 {
243 return mRanges && mRanges->IsComposing();
244 }
246 uint32_t TargetClauseOffset() const
247 {
248 return mRanges ? mRanges->TargetClauseOffset() : 0;
249 }
251 uint32_t RangeCount() const
252 {
253 return mRanges ? mRanges->Length() : 0;
254 }
255 };
257 /******************************************************************************
258 * mozilla::WidgetCompositionEvent
259 ******************************************************************************/
261 class WidgetCompositionEvent : public WidgetGUIEvent
262 {
263 private:
264 friend class mozilla::dom::PBrowserParent;
265 friend class mozilla::dom::PBrowserChild;
267 WidgetCompositionEvent()
268 : mSeqno(kLatestSeqno)
269 {
270 }
272 public:
273 uint32_t mSeqno;
275 public:
276 virtual WidgetCompositionEvent* AsCompositionEvent() MOZ_OVERRIDE
277 {
278 return this;
279 }
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 }
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 }
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;
309 void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
310 bool aCopyTargets)
311 {
312 AssignGUIEventData(aEvent, aCopyTargets);
314 data = aEvent.data;
315 }
316 };
318 /******************************************************************************
319 * mozilla::WidgetQueryContentEvent
320 ******************************************************************************/
322 class WidgetQueryContentEvent : public WidgetGUIEvent
323 {
324 private:
325 friend class dom::PBrowserParent;
326 friend class dom::PBrowserChild;
328 WidgetQueryContentEvent()
329 {
330 MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
331 }
333 public:
334 virtual WidgetQueryContentEvent* AsQueryContentEvent() MOZ_OVERRIDE
335 {
336 return this;
337 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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;
434 enum
435 {
436 NOT_FOUND = UINT32_MAX
437 };
439 // values of mComputedScrollAction
440 enum
441 {
442 SCROLL_ACTION_NONE,
443 SCROLL_ACTION_LINE,
444 SCROLL_ACTION_PAGE
445 };
446 };
448 /******************************************************************************
449 * mozilla::WidgetSelectionEvent
450 ******************************************************************************/
452 class WidgetSelectionEvent : public WidgetGUIEvent
453 {
454 private:
455 friend class mozilla::dom::PBrowserParent;
456 friend class mozilla::dom::PBrowserChild;
458 WidgetSelectionEvent()
459 : mSeqno(kLatestSeqno)
460 , mOffset(0)
461 , mLength(0)
462 , mReversed(false)
463 , mExpandToClusterBoundary(true)
464 , mSucceeded(false)
465 {
466 }
468 public:
469 uint32_t mSeqno;
471 public:
472 virtual WidgetSelectionEvent* AsSelectionEvent() MOZ_OVERRIDE
473 {
474 return this;
475 }
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 }
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 }
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 };
512 /******************************************************************************
513 * mozilla::InternalEditorInputEvent
514 ******************************************************************************/
516 class InternalEditorInputEvent : public InternalUIEvent
517 {
518 private:
519 InternalEditorInputEvent()
520 : mIsComposing(false)
521 {
522 }
524 public:
525 virtual InternalEditorInputEvent* AsEditorInputEvent() MOZ_OVERRIDE
526 {
527 return this;
528 }
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 }
541 mFlags.mBubbles = true;
542 mFlags.mCancelable = false;
543 }
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 }
557 bool mIsComposing;
559 void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent,
560 bool aCopyTargets)
561 {
562 AssignUIEventData(aEvent, aCopyTargets);
564 mIsComposing = aEvent.mIsComposing;
565 }
566 };
568 } // namespace mozilla
570 #endif // mozilla_TextEvents_h__