michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_TextEvents_h__ michael@0: #define mozilla_TextEvents_h__ michael@0: michael@0: #include michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/BasicEvents.h" michael@0: #include "mozilla/EventForwards.h" // for KeyNameIndex, temporarily michael@0: #include "mozilla/TextRange.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIDOMKeyEvent.h" michael@0: #include "nsITransferable.h" michael@0: #include "nsRect.h" michael@0: #include "nsStringGlue.h" michael@0: #include "nsTArray.h" michael@0: michael@0: /****************************************************************************** michael@0: * virtual keycode values michael@0: ******************************************************************************/ michael@0: michael@0: #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode michael@0: michael@0: enum michael@0: { michael@0: #include "mozilla/VirtualKeyCodeList.h" michael@0: }; michael@0: michael@0: #undef NS_DEFINE_VK michael@0: michael@0: #define kLatestSeqno UINT32_MAX michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace dom { michael@0: class PBrowserParent; michael@0: class PBrowserChild; michael@0: } // namespace dom michael@0: namespace plugins { michael@0: class PPluginInstanceChild; michael@0: } // namespace plugins michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::AlternativeCharCode michael@0: * michael@0: * This stores alternative charCode values of a key event with some modifiers. michael@0: * The stored values proper for testing shortcut key or access key. michael@0: ******************************************************************************/ michael@0: michael@0: struct AlternativeCharCode michael@0: { michael@0: AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode) : michael@0: mUnshiftedCharCode(aUnshiftedCharCode), mShiftedCharCode(aShiftedCharCode) michael@0: { michael@0: } michael@0: uint32_t mUnshiftedCharCode; michael@0: uint32_t mShiftedCharCode; michael@0: }; michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::WidgetKeyboardEvent michael@0: ******************************************************************************/ michael@0: michael@0: class WidgetKeyboardEvent : public WidgetInputEvent michael@0: { michael@0: private: michael@0: friend class dom::PBrowserParent; michael@0: friend class dom::PBrowserChild; michael@0: michael@0: WidgetKeyboardEvent() michael@0: { michael@0: } michael@0: michael@0: public: michael@0: virtual WidgetKeyboardEvent* AsKeyboardEvent() MOZ_OVERRIDE { return this; } michael@0: michael@0: WidgetKeyboardEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) michael@0: : WidgetInputEvent(aIsTrusted, aMessage, aWidget, NS_KEY_EVENT) michael@0: , keyCode(0) michael@0: , charCode(0) michael@0: , location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD) michael@0: , isChar(false) michael@0: , mIsRepeat(false) michael@0: , mIsComposing(false) michael@0: , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified) michael@0: , mNativeKeyEvent(nullptr) michael@0: , mUniqueId(0) michael@0: { michael@0: } michael@0: michael@0: virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE michael@0: { michael@0: MOZ_ASSERT(eventStructType == NS_KEY_EVENT, michael@0: "Duplicate() must be overridden by sub class"); michael@0: // Not copying widget, it is a weak reference. michael@0: WidgetKeyboardEvent* result = michael@0: new WidgetKeyboardEvent(false, message, nullptr); michael@0: result->AssignKeyEventData(*this, true); michael@0: result->mFlags = mFlags; michael@0: return result; michael@0: } michael@0: michael@0: // A DOM keyCode value or 0. If a keypress event whose charCode is 0, this michael@0: // should be 0. michael@0: uint32_t keyCode; michael@0: // If the instance is a keypress event of a printable key, this is a UTF-16 michael@0: // value of the key. Otherwise, 0. This value must not be a control michael@0: // character when some modifiers are active. Then, this value should be an michael@0: // unmodified value except Shift and AltGr. michael@0: uint32_t charCode; michael@0: // One of nsIDOMKeyEvent::DOM_KEY_LOCATION_* michael@0: uint32_t location; michael@0: // OS translated Unicode chars which are used for accesskey and accelkey michael@0: // handling. The handlers will try from first character to last character. michael@0: nsTArray alternativeCharCodes; michael@0: // Indicates whether the event signifies a printable character michael@0: bool isChar; michael@0: // Indicates whether the event is generated by auto repeat or not. michael@0: // if this is keyup event, always false. michael@0: bool mIsRepeat; michael@0: // Indicates whether the event is generated during IME (or deadkey) michael@0: // composition. This is initialized by EventStateManager. So, key event michael@0: // dispatchers don't need to initialize this. michael@0: bool mIsComposing; michael@0: // DOM KeyboardEvent.key michael@0: KeyNameIndex mKeyNameIndex; michael@0: // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING. michael@0: nsString mKeyValue; michael@0: // OS-specific native event can optionally be preserved michael@0: void* mNativeKeyEvent; michael@0: // Unique id associated with a keydown / keypress event. Used in identifing michael@0: // keypress events for removal from async event dispatch queue in metrofx michael@0: // after preventDefault is called on keydown events. It's ok if this wraps michael@0: // over long periods. michael@0: uint32_t mUniqueId; michael@0: michael@0: void GetDOMKeyName(nsAString& aKeyName) michael@0: { michael@0: if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) { michael@0: aKeyName = mKeyValue; michael@0: return; michael@0: } michael@0: GetDOMKeyName(mKeyNameIndex, aKeyName); michael@0: } michael@0: michael@0: static void GetDOMKeyName(mozilla::KeyNameIndex aKeyNameIndex, michael@0: nsAString& aKeyName); michael@0: michael@0: static const char* GetCommandStr(Command aCommand); michael@0: michael@0: void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets) michael@0: { michael@0: AssignInputEventData(aEvent, aCopyTargets); michael@0: michael@0: keyCode = aEvent.keyCode; michael@0: charCode = aEvent.charCode; michael@0: location = aEvent.location; michael@0: alternativeCharCodes = aEvent.alternativeCharCodes; michael@0: isChar = aEvent.isChar; michael@0: mIsRepeat = aEvent.mIsRepeat; michael@0: mIsComposing = aEvent.mIsComposing; michael@0: mKeyNameIndex = aEvent.mKeyNameIndex; michael@0: mKeyValue = aEvent.mKeyValue; michael@0: // Don't copy mNativeKeyEvent because it may be referred after its instance michael@0: // is destroyed. michael@0: mNativeKeyEvent = nullptr; michael@0: mUniqueId = aEvent.mUniqueId; michael@0: } michael@0: }; michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::WidgetTextEvent michael@0: * michael@0: * XXX WidgetTextEvent is fired with compositionupdate event almost every time. michael@0: * This wastes performance and the cost of mantaining each platform's michael@0: * implementation. Therefore, we should merge WidgetTextEvent and michael@0: * WidgetCompositionEvent. Then, DOM compositionupdate should be fired michael@0: * from TextComposition automatically. michael@0: ******************************************************************************/ michael@0: michael@0: class WidgetTextEvent : public WidgetGUIEvent michael@0: { michael@0: private: michael@0: friend class dom::PBrowserParent; michael@0: friend class dom::PBrowserChild; michael@0: friend class plugins::PPluginInstanceChild; michael@0: michael@0: WidgetTextEvent() michael@0: : mSeqno(kLatestSeqno) michael@0: , isChar(false) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: uint32_t mSeqno; michael@0: michael@0: public: michael@0: virtual WidgetTextEvent* AsTextEvent() MOZ_OVERRIDE { return this; } michael@0: michael@0: WidgetTextEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) michael@0: : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_TEXT_EVENT) michael@0: , mSeqno(kLatestSeqno) michael@0: , isChar(false) michael@0: { michael@0: } michael@0: michael@0: virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE michael@0: { michael@0: MOZ_ASSERT(eventStructType == NS_TEXT_EVENT, michael@0: "Duplicate() must be overridden by sub class"); michael@0: // Not copying widget, it is a weak reference. michael@0: WidgetTextEvent* result = new WidgetTextEvent(false, message, nullptr); michael@0: result->AssignTextEventData(*this, true); michael@0: result->mFlags = mFlags; michael@0: return result; michael@0: } michael@0: michael@0: // The composition string or the commit string. michael@0: nsString theText; michael@0: // Indicates whether the event signifies printable text. michael@0: // XXX This is not a standard, and most platforms don't set this properly. michael@0: // So, perhaps, we can get rid of this. michael@0: bool isChar; michael@0: michael@0: nsRefPtr mRanges; michael@0: michael@0: void AssignTextEventData(const WidgetTextEvent& aEvent, bool aCopyTargets) michael@0: { michael@0: AssignGUIEventData(aEvent, aCopyTargets); michael@0: michael@0: isChar = aEvent.isChar; michael@0: michael@0: // Currently, we don't need to copy the other members because they are michael@0: // for internal use only (not available from JS). michael@0: } michael@0: michael@0: bool IsComposing() const michael@0: { michael@0: return mRanges && mRanges->IsComposing(); michael@0: } michael@0: michael@0: uint32_t TargetClauseOffset() const michael@0: { michael@0: return mRanges ? mRanges->TargetClauseOffset() : 0; michael@0: } michael@0: michael@0: uint32_t RangeCount() const michael@0: { michael@0: return mRanges ? mRanges->Length() : 0; michael@0: } michael@0: }; michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::WidgetCompositionEvent michael@0: ******************************************************************************/ michael@0: michael@0: class WidgetCompositionEvent : public WidgetGUIEvent michael@0: { michael@0: private: michael@0: friend class mozilla::dom::PBrowserParent; michael@0: friend class mozilla::dom::PBrowserChild; michael@0: michael@0: WidgetCompositionEvent() michael@0: : mSeqno(kLatestSeqno) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: uint32_t mSeqno; michael@0: michael@0: public: michael@0: virtual WidgetCompositionEvent* AsCompositionEvent() MOZ_OVERRIDE michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: WidgetCompositionEvent(bool aIsTrusted, uint32_t aMessage, michael@0: nsIWidget* aWidget) michael@0: : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_COMPOSITION_EVENT) michael@0: , mSeqno(kLatestSeqno) michael@0: { michael@0: // XXX compositionstart is cancelable in draft of DOM3 Events. michael@0: // However, it doesn't make sense for us, we cannot cancel composition michael@0: // when we send compositionstart event. michael@0: mFlags.mCancelable = false; michael@0: } michael@0: michael@0: virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE michael@0: { michael@0: MOZ_ASSERT(eventStructType == NS_COMPOSITION_EVENT, michael@0: "Duplicate() must be overridden by sub class"); michael@0: // Not copying widget, it is a weak reference. michael@0: WidgetCompositionEvent* result = michael@0: new WidgetCompositionEvent(false, message, nullptr); michael@0: result->AssignCompositionEventData(*this, true); michael@0: result->mFlags = mFlags; michael@0: return result; michael@0: } michael@0: michael@0: // The composition string or the commit string. If the instance is a michael@0: // compositionstart event, this is initialized with selected text by michael@0: // TextComposition automatically. michael@0: nsString data; michael@0: michael@0: void AssignCompositionEventData(const WidgetCompositionEvent& aEvent, michael@0: bool aCopyTargets) michael@0: { michael@0: AssignGUIEventData(aEvent, aCopyTargets); michael@0: michael@0: data = aEvent.data; michael@0: } michael@0: }; michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::WidgetQueryContentEvent michael@0: ******************************************************************************/ michael@0: michael@0: class WidgetQueryContentEvent : public WidgetGUIEvent michael@0: { michael@0: private: michael@0: friend class dom::PBrowserParent; michael@0: friend class dom::PBrowserChild; michael@0: michael@0: WidgetQueryContentEvent() michael@0: { michael@0: MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments"); michael@0: } michael@0: michael@0: public: michael@0: virtual WidgetQueryContentEvent* AsQueryContentEvent() MOZ_OVERRIDE michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: WidgetQueryContentEvent(bool aIsTrusted, uint32_t aMessage, michael@0: nsIWidget* aWidget) michael@0: : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_QUERY_CONTENT_EVENT) michael@0: , mSucceeded(false) michael@0: , mWasAsync(false) michael@0: , mUseNativeLineBreak(true) michael@0: { michael@0: } michael@0: michael@0: virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE michael@0: { michael@0: // This event isn't an internal event of any DOM event. michael@0: NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), michael@0: "WidgetQueryContentEvent needs to support Duplicate()"); michael@0: MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()"); michael@0: return nullptr; michael@0: } michael@0: michael@0: void InitForQueryTextContent(uint32_t aOffset, uint32_t aLength, michael@0: bool aUseNativeLineBreak = true) michael@0: { michael@0: NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT, michael@0: "wrong initializer is called"); michael@0: mInput.mOffset = aOffset; michael@0: mInput.mLength = aLength; michael@0: mUseNativeLineBreak = aUseNativeLineBreak; michael@0: } michael@0: michael@0: void InitForQueryCaretRect(uint32_t aOffset, michael@0: bool aUseNativeLineBreak = true) michael@0: { michael@0: NS_ASSERTION(message == NS_QUERY_CARET_RECT, michael@0: "wrong initializer is called"); michael@0: mInput.mOffset = aOffset; michael@0: mUseNativeLineBreak = aUseNativeLineBreak; michael@0: } michael@0: michael@0: void InitForQueryTextRect(uint32_t aOffset, uint32_t aLength, michael@0: bool aUseNativeLineBreak = true) michael@0: { michael@0: NS_ASSERTION(message == NS_QUERY_TEXT_RECT, michael@0: "wrong initializer is called"); michael@0: mInput.mOffset = aOffset; michael@0: mInput.mLength = aLength; michael@0: mUseNativeLineBreak = aUseNativeLineBreak; michael@0: } michael@0: michael@0: void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint) michael@0: { michael@0: NS_ASSERTION(message == NS_QUERY_DOM_WIDGET_HITTEST, michael@0: "wrong initializer is called"); michael@0: refPoint = aPoint; michael@0: } michael@0: michael@0: uint32_t GetSelectionStart(void) const michael@0: { michael@0: NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, michael@0: "not querying selection"); michael@0: return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0); michael@0: } michael@0: michael@0: uint32_t GetSelectionEnd(void) const michael@0: { michael@0: NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, michael@0: "not querying selection"); michael@0: return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length()); michael@0: } michael@0: michael@0: bool mSucceeded; michael@0: bool mWasAsync; michael@0: bool mUseNativeLineBreak; michael@0: struct michael@0: { michael@0: uint32_t mOffset; michael@0: uint32_t mLength; michael@0: } mInput; michael@0: struct michael@0: { michael@0: void* mContentsRoot; michael@0: uint32_t mOffset; michael@0: nsString mString; michael@0: // Finally, the coordinates is system coordinates. michael@0: nsIntRect mRect; michael@0: // The return widget has the caret. This is set at all query events. michael@0: nsIWidget* mFocusedWidget; michael@0: // true if selection is reversed (end < start) michael@0: bool mReversed; michael@0: // true if the selection exists michael@0: bool mHasSelection; michael@0: // true if DOM element under mouse belongs to widget michael@0: bool mWidgetIsHit; michael@0: // used by NS_QUERY_SELECTION_AS_TRANSFERABLE michael@0: nsCOMPtr mTransferable; michael@0: } mReply; michael@0: michael@0: enum michael@0: { michael@0: NOT_FOUND = UINT32_MAX michael@0: }; michael@0: michael@0: // values of mComputedScrollAction michael@0: enum michael@0: { michael@0: SCROLL_ACTION_NONE, michael@0: SCROLL_ACTION_LINE, michael@0: SCROLL_ACTION_PAGE michael@0: }; michael@0: }; michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::WidgetSelectionEvent michael@0: ******************************************************************************/ michael@0: michael@0: class WidgetSelectionEvent : public WidgetGUIEvent michael@0: { michael@0: private: michael@0: friend class mozilla::dom::PBrowserParent; michael@0: friend class mozilla::dom::PBrowserChild; michael@0: michael@0: WidgetSelectionEvent() michael@0: : mSeqno(kLatestSeqno) michael@0: , mOffset(0) michael@0: , mLength(0) michael@0: , mReversed(false) michael@0: , mExpandToClusterBoundary(true) michael@0: , mSucceeded(false) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: uint32_t mSeqno; michael@0: michael@0: public: michael@0: virtual WidgetSelectionEvent* AsSelectionEvent() MOZ_OVERRIDE michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: WidgetSelectionEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) michael@0: : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_SELECTION_EVENT) michael@0: , mSeqno(kLatestSeqno) michael@0: , mOffset(0) michael@0: , mLength(0) michael@0: , mReversed(false) michael@0: , mExpandToClusterBoundary(true) michael@0: , mSucceeded(false) michael@0: , mUseNativeLineBreak(true) michael@0: { michael@0: } michael@0: michael@0: virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE michael@0: { michael@0: // This event isn't an internal event of any DOM event. michael@0: NS_ASSERTION(!IsAllowedToDispatchDOMEvent(), michael@0: "WidgetSelectionEvent needs to support Duplicate()"); michael@0: MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()"); michael@0: return nullptr; michael@0: } michael@0: michael@0: // Start offset of selection michael@0: uint32_t mOffset; michael@0: // Length of selection michael@0: uint32_t mLength; michael@0: // Selection "anchor" should be in front michael@0: bool mReversed; michael@0: // Cluster-based or character-based michael@0: bool mExpandToClusterBoundary; michael@0: // true if setting selection succeeded. michael@0: bool mSucceeded; michael@0: // true if native line breaks are used for mOffset and mLength michael@0: bool mUseNativeLineBreak; michael@0: }; michael@0: michael@0: /****************************************************************************** michael@0: * mozilla::InternalEditorInputEvent michael@0: ******************************************************************************/ michael@0: michael@0: class InternalEditorInputEvent : public InternalUIEvent michael@0: { michael@0: private: michael@0: InternalEditorInputEvent() michael@0: : mIsComposing(false) michael@0: { michael@0: } michael@0: michael@0: public: michael@0: virtual InternalEditorInputEvent* AsEditorInputEvent() MOZ_OVERRIDE michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: InternalEditorInputEvent(bool aIsTrusted, uint32_t aMessage, michael@0: nsIWidget* aWidget) michael@0: : InternalUIEvent(aIsTrusted, aMessage, aWidget, NS_EDITOR_INPUT_EVENT) michael@0: , mIsComposing(false) michael@0: { michael@0: if (!aIsTrusted) { michael@0: mFlags.mBubbles = false; michael@0: mFlags.mCancelable = false; michael@0: return; michael@0: } michael@0: michael@0: mFlags.mBubbles = true; michael@0: mFlags.mCancelable = false; michael@0: } michael@0: michael@0: virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE michael@0: { michael@0: MOZ_ASSERT(eventStructType == NS_EDITOR_INPUT_EVENT, michael@0: "Duplicate() must be overridden by sub class"); michael@0: // Not copying widget, it is a weak reference. michael@0: InternalEditorInputEvent* result = michael@0: new InternalEditorInputEvent(false, message, nullptr); michael@0: result->AssignEditorInputEventData(*this, true); michael@0: result->mFlags = mFlags; michael@0: return result; michael@0: } michael@0: michael@0: bool mIsComposing; michael@0: michael@0: void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent, michael@0: bool aCopyTargets) michael@0: { michael@0: AssignUIEventData(aEvent, aCopyTargets); michael@0: michael@0: mIsComposing = aEvent.mIsComposing; michael@0: } michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_TextEvents_h__