1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/TextEvents.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,570 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef mozilla_TextEvents_h__ 1.10 +#define mozilla_TextEvents_h__ 1.11 + 1.12 +#include <stdint.h> 1.13 + 1.14 +#include "mozilla/Assertions.h" 1.15 +#include "mozilla/BasicEvents.h" 1.16 +#include "mozilla/EventForwards.h" // for KeyNameIndex, temporarily 1.17 +#include "mozilla/TextRange.h" 1.18 +#include "nsCOMPtr.h" 1.19 +#include "nsIDOMKeyEvent.h" 1.20 +#include "nsITransferable.h" 1.21 +#include "nsRect.h" 1.22 +#include "nsStringGlue.h" 1.23 +#include "nsTArray.h" 1.24 + 1.25 +/****************************************************************************** 1.26 + * virtual keycode values 1.27 + ******************************************************************************/ 1.28 + 1.29 +#define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode 1.30 + 1.31 +enum 1.32 +{ 1.33 +#include "mozilla/VirtualKeyCodeList.h" 1.34 +}; 1.35 + 1.36 +#undef NS_DEFINE_VK 1.37 + 1.38 +#define kLatestSeqno UINT32_MAX 1.39 + 1.40 +namespace mozilla { 1.41 + 1.42 +namespace dom { 1.43 + class PBrowserParent; 1.44 + class PBrowserChild; 1.45 +} // namespace dom 1.46 +namespace plugins { 1.47 + class PPluginInstanceChild; 1.48 +} // namespace plugins 1.49 + 1.50 +/****************************************************************************** 1.51 + * mozilla::AlternativeCharCode 1.52 + * 1.53 + * This stores alternative charCode values of a key event with some modifiers. 1.54 + * The stored values proper for testing shortcut key or access key. 1.55 + ******************************************************************************/ 1.56 + 1.57 +struct AlternativeCharCode 1.58 +{ 1.59 + AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode) : 1.60 + mUnshiftedCharCode(aUnshiftedCharCode), mShiftedCharCode(aShiftedCharCode) 1.61 + { 1.62 + } 1.63 + uint32_t mUnshiftedCharCode; 1.64 + uint32_t mShiftedCharCode; 1.65 +}; 1.66 + 1.67 +/****************************************************************************** 1.68 + * mozilla::WidgetKeyboardEvent 1.69 + ******************************************************************************/ 1.70 + 1.71 +class WidgetKeyboardEvent : public WidgetInputEvent 1.72 +{ 1.73 +private: 1.74 + friend class dom::PBrowserParent; 1.75 + friend class dom::PBrowserChild; 1.76 + 1.77 + WidgetKeyboardEvent() 1.78 + { 1.79 + } 1.80 + 1.81 +public: 1.82 + virtual WidgetKeyboardEvent* AsKeyboardEvent() MOZ_OVERRIDE { return this; } 1.83 + 1.84 + WidgetKeyboardEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) 1.85 + : WidgetInputEvent(aIsTrusted, aMessage, aWidget, NS_KEY_EVENT) 1.86 + , keyCode(0) 1.87 + , charCode(0) 1.88 + , location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD) 1.89 + , isChar(false) 1.90 + , mIsRepeat(false) 1.91 + , mIsComposing(false) 1.92 + , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified) 1.93 + , mNativeKeyEvent(nullptr) 1.94 + , mUniqueId(0) 1.95 + { 1.96 + } 1.97 + 1.98 + virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE 1.99 + { 1.100 + MOZ_ASSERT(eventStructType == NS_KEY_EVENT, 1.101 + "Duplicate() must be overridden by sub class"); 1.102 + // Not copying widget, it is a weak reference. 1.103 + WidgetKeyboardEvent* result = 1.104 + new WidgetKeyboardEvent(false, message, nullptr); 1.105 + result->AssignKeyEventData(*this, true); 1.106 + result->mFlags = mFlags; 1.107 + return result; 1.108 + } 1.109 + 1.110 + // A DOM keyCode value or 0. If a keypress event whose charCode is 0, this 1.111 + // should be 0. 1.112 + uint32_t keyCode; 1.113 + // If the instance is a keypress event of a printable key, this is a UTF-16 1.114 + // value of the key. Otherwise, 0. This value must not be a control 1.115 + // character when some modifiers are active. Then, this value should be an 1.116 + // unmodified value except Shift and AltGr. 1.117 + uint32_t charCode; 1.118 + // One of nsIDOMKeyEvent::DOM_KEY_LOCATION_* 1.119 + uint32_t location; 1.120 + // OS translated Unicode chars which are used for accesskey and accelkey 1.121 + // handling. The handlers will try from first character to last character. 1.122 + nsTArray<AlternativeCharCode> alternativeCharCodes; 1.123 + // Indicates whether the event signifies a printable character 1.124 + bool isChar; 1.125 + // Indicates whether the event is generated by auto repeat or not. 1.126 + // if this is keyup event, always false. 1.127 + bool mIsRepeat; 1.128 + // Indicates whether the event is generated during IME (or deadkey) 1.129 + // composition. This is initialized by EventStateManager. So, key event 1.130 + // dispatchers don't need to initialize this. 1.131 + bool mIsComposing; 1.132 + // DOM KeyboardEvent.key 1.133 + KeyNameIndex mKeyNameIndex; 1.134 + // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING. 1.135 + nsString mKeyValue; 1.136 + // OS-specific native event can optionally be preserved 1.137 + void* mNativeKeyEvent; 1.138 + // Unique id associated with a keydown / keypress event. Used in identifing 1.139 + // keypress events for removal from async event dispatch queue in metrofx 1.140 + // after preventDefault is called on keydown events. It's ok if this wraps 1.141 + // over long periods. 1.142 + uint32_t mUniqueId; 1.143 + 1.144 + void GetDOMKeyName(nsAString& aKeyName) 1.145 + { 1.146 + if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) { 1.147 + aKeyName = mKeyValue; 1.148 + return; 1.149 + } 1.150 + GetDOMKeyName(mKeyNameIndex, aKeyName); 1.151 + } 1.152 + 1.153 + static void GetDOMKeyName(mozilla::KeyNameIndex aKeyNameIndex, 1.154 + nsAString& aKeyName); 1.155 + 1.156 + static const char* GetCommandStr(Command aCommand); 1.157 + 1.158 + void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets) 1.159 + { 1.160 + AssignInputEventData(aEvent, aCopyTargets); 1.161 + 1.162 + keyCode = aEvent.keyCode; 1.163 + charCode = aEvent.charCode; 1.164 + location = aEvent.location; 1.165 + alternativeCharCodes = aEvent.alternativeCharCodes; 1.166 + isChar = aEvent.isChar; 1.167 + mIsRepeat = aEvent.mIsRepeat; 1.168 + mIsComposing = aEvent.mIsComposing; 1.169 + mKeyNameIndex = aEvent.mKeyNameIndex; 1.170 + mKeyValue = aEvent.mKeyValue; 1.171 + // Don't copy mNativeKeyEvent because it may be referred after its instance 1.172 + // is destroyed. 1.173 + mNativeKeyEvent = nullptr; 1.174 + mUniqueId = aEvent.mUniqueId; 1.175 + } 1.176 +}; 1.177 + 1.178 +/****************************************************************************** 1.179 + * mozilla::WidgetTextEvent 1.180 + * 1.181 + * XXX WidgetTextEvent is fired with compositionupdate event almost every time. 1.182 + * This wastes performance and the cost of mantaining each platform's 1.183 + * implementation. Therefore, we should merge WidgetTextEvent and 1.184 + * WidgetCompositionEvent. Then, DOM compositionupdate should be fired 1.185 + * from TextComposition automatically. 1.186 + ******************************************************************************/ 1.187 + 1.188 +class WidgetTextEvent : public WidgetGUIEvent 1.189 +{ 1.190 +private: 1.191 + friend class dom::PBrowserParent; 1.192 + friend class dom::PBrowserChild; 1.193 + friend class plugins::PPluginInstanceChild; 1.194 + 1.195 + WidgetTextEvent() 1.196 + : mSeqno(kLatestSeqno) 1.197 + , isChar(false) 1.198 + { 1.199 + } 1.200 + 1.201 +public: 1.202 + uint32_t mSeqno; 1.203 + 1.204 +public: 1.205 + virtual WidgetTextEvent* AsTextEvent() MOZ_OVERRIDE { return this; } 1.206 + 1.207 + WidgetTextEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) 1.208 + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_TEXT_EVENT) 1.209 + , mSeqno(kLatestSeqno) 1.210 + , isChar(false) 1.211 + { 1.212 + } 1.213 + 1.214 + virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE 1.215 + { 1.216 + MOZ_ASSERT(eventStructType == NS_TEXT_EVENT, 1.217 + "Duplicate() must be overridden by sub class"); 1.218 + // Not copying widget, it is a weak reference. 1.219 + WidgetTextEvent* result = new WidgetTextEvent(false, message, nullptr); 1.220 + result->AssignTextEventData(*this, true); 1.221 + result->mFlags = mFlags; 1.222 + return result; 1.223 + } 1.224 + 1.225 + // The composition string or the commit string. 1.226 + nsString theText; 1.227 + // Indicates whether the event signifies printable text. 1.228 + // XXX This is not a standard, and most platforms don't set this properly. 1.229 + // So, perhaps, we can get rid of this. 1.230 + bool isChar; 1.231 + 1.232 + nsRefPtr<TextRangeArray> mRanges; 1.233 + 1.234 + void AssignTextEventData(const WidgetTextEvent& aEvent, bool aCopyTargets) 1.235 + { 1.236 + AssignGUIEventData(aEvent, aCopyTargets); 1.237 + 1.238 + isChar = aEvent.isChar; 1.239 + 1.240 + // Currently, we don't need to copy the other members because they are 1.241 + // for internal use only (not available from JS). 1.242 + } 1.243 + 1.244 + bool IsComposing() const 1.245 + { 1.246 + return mRanges && mRanges->IsComposing(); 1.247 + } 1.248 + 1.249 + uint32_t TargetClauseOffset() const 1.250 + { 1.251 + return mRanges ? mRanges->TargetClauseOffset() : 0; 1.252 + } 1.253 + 1.254 + uint32_t RangeCount() const 1.255 + { 1.256 + return mRanges ? mRanges->Length() : 0; 1.257 + } 1.258 +}; 1.259 + 1.260 +/****************************************************************************** 1.261 + * mozilla::WidgetCompositionEvent 1.262 + ******************************************************************************/ 1.263 + 1.264 +class WidgetCompositionEvent : public WidgetGUIEvent 1.265 +{ 1.266 +private: 1.267 + friend class mozilla::dom::PBrowserParent; 1.268 + friend class mozilla::dom::PBrowserChild; 1.269 + 1.270 + WidgetCompositionEvent() 1.271 + : mSeqno(kLatestSeqno) 1.272 + { 1.273 + } 1.274 + 1.275 +public: 1.276 + uint32_t mSeqno; 1.277 + 1.278 +public: 1.279 + virtual WidgetCompositionEvent* AsCompositionEvent() MOZ_OVERRIDE 1.280 + { 1.281 + return this; 1.282 + } 1.283 + 1.284 + WidgetCompositionEvent(bool aIsTrusted, uint32_t aMessage, 1.285 + nsIWidget* aWidget) 1.286 + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_COMPOSITION_EVENT) 1.287 + , mSeqno(kLatestSeqno) 1.288 + { 1.289 + // XXX compositionstart is cancelable in draft of DOM3 Events. 1.290 + // However, it doesn't make sense for us, we cannot cancel composition 1.291 + // when we send compositionstart event. 1.292 + mFlags.mCancelable = false; 1.293 + } 1.294 + 1.295 + virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE 1.296 + { 1.297 + MOZ_ASSERT(eventStructType == NS_COMPOSITION_EVENT, 1.298 + "Duplicate() must be overridden by sub class"); 1.299 + // Not copying widget, it is a weak reference. 1.300 + WidgetCompositionEvent* result = 1.301 + new WidgetCompositionEvent(false, message, nullptr); 1.302 + result->AssignCompositionEventData(*this, true); 1.303 + result->mFlags = mFlags; 1.304 + return result; 1.305 + } 1.306 + 1.307 + // The composition string or the commit string. If the instance is a 1.308 + // compositionstart event, this is initialized with selected text by 1.309 + // TextComposition automatically. 1.310 + nsString data; 1.311 + 1.312 + void AssignCompositionEventData(const WidgetCompositionEvent& aEvent, 1.313 + bool aCopyTargets) 1.314 + { 1.315 + AssignGUIEventData(aEvent, aCopyTargets); 1.316 + 1.317 + data = aEvent.data; 1.318 + } 1.319 +}; 1.320 + 1.321 +/****************************************************************************** 1.322 + * mozilla::WidgetQueryContentEvent 1.323 + ******************************************************************************/ 1.324 + 1.325 +class WidgetQueryContentEvent : public WidgetGUIEvent 1.326 +{ 1.327 +private: 1.328 + friend class dom::PBrowserParent; 1.329 + friend class dom::PBrowserChild; 1.330 + 1.331 + WidgetQueryContentEvent() 1.332 + { 1.333 + MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments"); 1.334 + } 1.335 + 1.336 +public: 1.337 + virtual WidgetQueryContentEvent* AsQueryContentEvent() MOZ_OVERRIDE 1.338 + { 1.339 + return this; 1.340 + } 1.341 + 1.342 + WidgetQueryContentEvent(bool aIsTrusted, uint32_t aMessage, 1.343 + nsIWidget* aWidget) 1.344 + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_QUERY_CONTENT_EVENT) 1.345 + , mSucceeded(false) 1.346 + , mWasAsync(false) 1.347 + , mUseNativeLineBreak(true) 1.348 + { 1.349 + } 1.350 + 1.351 + virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE 1.352 + { 1.353 + // This event isn't an internal event of any DOM event. 1.354 + NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), 1.355 + "WidgetQueryContentEvent needs to support Duplicate()"); 1.356 + MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()"); 1.357 + return nullptr; 1.358 + } 1.359 + 1.360 + void InitForQueryTextContent(uint32_t aOffset, uint32_t aLength, 1.361 + bool aUseNativeLineBreak = true) 1.362 + { 1.363 + NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT, 1.364 + "wrong initializer is called"); 1.365 + mInput.mOffset = aOffset; 1.366 + mInput.mLength = aLength; 1.367 + mUseNativeLineBreak = aUseNativeLineBreak; 1.368 + } 1.369 + 1.370 + void InitForQueryCaretRect(uint32_t aOffset, 1.371 + bool aUseNativeLineBreak = true) 1.372 + { 1.373 + NS_ASSERTION(message == NS_QUERY_CARET_RECT, 1.374 + "wrong initializer is called"); 1.375 + mInput.mOffset = aOffset; 1.376 + mUseNativeLineBreak = aUseNativeLineBreak; 1.377 + } 1.378 + 1.379 + void InitForQueryTextRect(uint32_t aOffset, uint32_t aLength, 1.380 + bool aUseNativeLineBreak = true) 1.381 + { 1.382 + NS_ASSERTION(message == NS_QUERY_TEXT_RECT, 1.383 + "wrong initializer is called"); 1.384 + mInput.mOffset = aOffset; 1.385 + mInput.mLength = aLength; 1.386 + mUseNativeLineBreak = aUseNativeLineBreak; 1.387 + } 1.388 + 1.389 + void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint) 1.390 + { 1.391 + NS_ASSERTION(message == NS_QUERY_DOM_WIDGET_HITTEST, 1.392 + "wrong initializer is called"); 1.393 + refPoint = aPoint; 1.394 + } 1.395 + 1.396 + uint32_t GetSelectionStart(void) const 1.397 + { 1.398 + NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, 1.399 + "not querying selection"); 1.400 + return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0); 1.401 + } 1.402 + 1.403 + uint32_t GetSelectionEnd(void) const 1.404 + { 1.405 + NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, 1.406 + "not querying selection"); 1.407 + return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length()); 1.408 + } 1.409 + 1.410 + bool mSucceeded; 1.411 + bool mWasAsync; 1.412 + bool mUseNativeLineBreak; 1.413 + struct 1.414 + { 1.415 + uint32_t mOffset; 1.416 + uint32_t mLength; 1.417 + } mInput; 1.418 + struct 1.419 + { 1.420 + void* mContentsRoot; 1.421 + uint32_t mOffset; 1.422 + nsString mString; 1.423 + // Finally, the coordinates is system coordinates. 1.424 + nsIntRect mRect; 1.425 + // The return widget has the caret. This is set at all query events. 1.426 + nsIWidget* mFocusedWidget; 1.427 + // true if selection is reversed (end < start) 1.428 + bool mReversed; 1.429 + // true if the selection exists 1.430 + bool mHasSelection; 1.431 + // true if DOM element under mouse belongs to widget 1.432 + bool mWidgetIsHit; 1.433 + // used by NS_QUERY_SELECTION_AS_TRANSFERABLE 1.434 + nsCOMPtr<nsITransferable> mTransferable; 1.435 + } mReply; 1.436 + 1.437 + enum 1.438 + { 1.439 + NOT_FOUND = UINT32_MAX 1.440 + }; 1.441 + 1.442 + // values of mComputedScrollAction 1.443 + enum 1.444 + { 1.445 + SCROLL_ACTION_NONE, 1.446 + SCROLL_ACTION_LINE, 1.447 + SCROLL_ACTION_PAGE 1.448 + }; 1.449 +}; 1.450 + 1.451 +/****************************************************************************** 1.452 + * mozilla::WidgetSelectionEvent 1.453 + ******************************************************************************/ 1.454 + 1.455 +class WidgetSelectionEvent : public WidgetGUIEvent 1.456 +{ 1.457 +private: 1.458 + friend class mozilla::dom::PBrowserParent; 1.459 + friend class mozilla::dom::PBrowserChild; 1.460 + 1.461 + WidgetSelectionEvent() 1.462 + : mSeqno(kLatestSeqno) 1.463 + , mOffset(0) 1.464 + , mLength(0) 1.465 + , mReversed(false) 1.466 + , mExpandToClusterBoundary(true) 1.467 + , mSucceeded(false) 1.468 + { 1.469 + } 1.470 + 1.471 +public: 1.472 + uint32_t mSeqno; 1.473 + 1.474 +public: 1.475 + virtual WidgetSelectionEvent* AsSelectionEvent() MOZ_OVERRIDE 1.476 + { 1.477 + return this; 1.478 + } 1.479 + 1.480 + WidgetSelectionEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) 1.481 + : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_SELECTION_EVENT) 1.482 + , mSeqno(kLatestSeqno) 1.483 + , mOffset(0) 1.484 + , mLength(0) 1.485 + , mReversed(false) 1.486 + , mExpandToClusterBoundary(true) 1.487 + , mSucceeded(false) 1.488 + , mUseNativeLineBreak(true) 1.489 + { 1.490 + } 1.491 + 1.492 + virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE 1.493 + { 1.494 + // This event isn't an internal event of any DOM event. 1.495 + NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), 1.496 + "WidgetSelectionEvent needs to support Duplicate()"); 1.497 + MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()"); 1.498 + return nullptr; 1.499 + } 1.500 + 1.501 + // Start offset of selection 1.502 + uint32_t mOffset; 1.503 + // Length of selection 1.504 + uint32_t mLength; 1.505 + // Selection "anchor" should be in front 1.506 + bool mReversed; 1.507 + // Cluster-based or character-based 1.508 + bool mExpandToClusterBoundary; 1.509 + // true if setting selection succeeded. 1.510 + bool mSucceeded; 1.511 + // true if native line breaks are used for mOffset and mLength 1.512 + bool mUseNativeLineBreak; 1.513 +}; 1.514 + 1.515 +/****************************************************************************** 1.516 + * mozilla::InternalEditorInputEvent 1.517 + ******************************************************************************/ 1.518 + 1.519 +class InternalEditorInputEvent : public InternalUIEvent 1.520 +{ 1.521 +private: 1.522 + InternalEditorInputEvent() 1.523 + : mIsComposing(false) 1.524 + { 1.525 + } 1.526 + 1.527 +public: 1.528 + virtual InternalEditorInputEvent* AsEditorInputEvent() MOZ_OVERRIDE 1.529 + { 1.530 + return this; 1.531 + } 1.532 + 1.533 + InternalEditorInputEvent(bool aIsTrusted, uint32_t aMessage, 1.534 + nsIWidget* aWidget) 1.535 + : InternalUIEvent(aIsTrusted, aMessage, aWidget, NS_EDITOR_INPUT_EVENT) 1.536 + , mIsComposing(false) 1.537 + { 1.538 + if (!aIsTrusted) { 1.539 + mFlags.mBubbles = false; 1.540 + mFlags.mCancelable = false; 1.541 + return; 1.542 + } 1.543 + 1.544 + mFlags.mBubbles = true; 1.545 + mFlags.mCancelable = false; 1.546 + } 1.547 + 1.548 + virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE 1.549 + { 1.550 + MOZ_ASSERT(eventStructType == NS_EDITOR_INPUT_EVENT, 1.551 + "Duplicate() must be overridden by sub class"); 1.552 + // Not copying widget, it is a weak reference. 1.553 + InternalEditorInputEvent* result = 1.554 + new InternalEditorInputEvent(false, message, nullptr); 1.555 + result->AssignEditorInputEventData(*this, true); 1.556 + result->mFlags = mFlags; 1.557 + return result; 1.558 + } 1.559 + 1.560 + bool mIsComposing; 1.561 + 1.562 + void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent, 1.563 + bool aCopyTargets) 1.564 + { 1.565 + AssignUIEventData(aEvent, aCopyTargets); 1.566 + 1.567 + mIsComposing = aEvent.mIsComposing; 1.568 + } 1.569 +}; 1.570 + 1.571 +} // namespace mozilla 1.572 + 1.573 +#endif // mozilla_TextEvents_h__