summaryrefslogtreecommitdiffstats
path: root/widget/TextEvents.h
diff options
context:
space:
mode:
Diffstat (limited to 'widget/TextEvents.h')
-rw-r--r--widget/TextEvents.h1014
1 files changed, 1014 insertions, 0 deletions
diff --git a/widget/TextEvents.h b/widget/TextEvents.h
new file mode 100644
index 000000000..6c2934114
--- /dev/null
+++ b/widget/TextEvents.h
@@ -0,0 +1,1014 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_TextEvents_h__
+#define mozilla_TextEvents_h__
+
+#include <stdint.h>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/BasicEvents.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/EventForwards.h" // for KeyNameIndex, temporarily
+#include "mozilla/TextRange.h"
+#include "mozilla/FontRange.h"
+#include "nsCOMPtr.h"
+#include "nsIDOMKeyEvent.h"
+#include "nsISelectionController.h"
+#include "nsISelectionListener.h"
+#include "nsITransferable.h"
+#include "nsRect.h"
+#include "nsStringGlue.h"
+#include "nsTArray.h"
+#include "WritingModes.h"
+
+class nsStringHashKey;
+template<class, class> class nsDataHashtable;
+
+/******************************************************************************
+ * virtual keycode values
+ ******************************************************************************/
+
+enum
+{
+#define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) NS_##aDOMKeyName = aDOMKeyCode,
+#include "mozilla/VirtualKeyCodeList.h"
+#undef NS_DEFINE_VK
+ NS_VK_UNKNOWN = 0xFF
+};
+
+namespace mozilla {
+
+const nsCString GetDOMKeyCodeName(uint32_t aKeyCode);
+
+namespace dom {
+ class PBrowserParent;
+ class PBrowserChild;
+} // namespace dom
+namespace plugins {
+ class PPluginInstanceChild;
+} // namespace plugins
+
+/******************************************************************************
+ * mozilla::AlternativeCharCode
+ *
+ * This stores alternative charCode values of a key event with some modifiers.
+ * The stored values proper for testing shortcut key or access key.
+ ******************************************************************************/
+
+struct AlternativeCharCode
+{
+ AlternativeCharCode() :
+ mUnshiftedCharCode(0), mShiftedCharCode(0)
+ {
+ }
+ AlternativeCharCode(uint32_t aUnshiftedCharCode, uint32_t aShiftedCharCode) :
+ mUnshiftedCharCode(aUnshiftedCharCode), mShiftedCharCode(aShiftedCharCode)
+ {
+ }
+ uint32_t mUnshiftedCharCode;
+ uint32_t mShiftedCharCode;
+};
+
+/******************************************************************************
+ * mozilla::ShortcutKeyCandidate
+ *
+ * This stores a candidate of shortcut key combination.
+ ******************************************************************************/
+
+struct ShortcutKeyCandidate
+{
+ ShortcutKeyCandidate(uint32_t aCharCode, bool aIgnoreShift)
+ : mCharCode(aCharCode)
+ , mIgnoreShift(aIgnoreShift)
+ {
+ }
+ // The mCharCode value which must match keyboard shortcut definition.
+ uint32_t mCharCode;
+ // true if Shift state can be ignored. Otherwise, Shift key state must
+ // match keyboard shortcut definition.
+ bool mIgnoreShift;
+};
+
+/******************************************************************************
+ * mozilla::WidgetKeyboardEvent
+ ******************************************************************************/
+
+class WidgetKeyboardEvent : public WidgetInputEvent
+{
+private:
+ friend class dom::PBrowserParent;
+ friend class dom::PBrowserChild;
+
+protected:
+ WidgetKeyboardEvent()
+ : mNativeKeyEvent(nullptr)
+ , mKeyCode(0)
+ , mCharCode(0)
+ , mPseudoCharCode(0)
+ , mLocation(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
+ , mAccessKeyForwardedToChild(false)
+ , mUniqueId(0)
+#ifdef XP_MACOSX
+ , mNativeModifierFlags(0)
+ , mNativeKeyCode(0)
+#endif // #ifdef XP_MACOSX
+ , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
+ , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
+ , mInputMethodAppState(eNotHandled)
+ , mIsChar(false)
+ , mIsRepeat(false)
+ , mIsComposing(false)
+ , mIsReserved(false)
+ , mIsSynthesizedByTIP(false)
+ {
+ }
+
+public:
+ virtual WidgetKeyboardEvent* AsKeyboardEvent() override { return this; }
+
+ WidgetKeyboardEvent(bool aIsTrusted, EventMessage aMessage,
+ nsIWidget* aWidget,
+ EventClassID aEventClassID = eKeyboardEventClass)
+ : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID)
+ , mNativeKeyEvent(nullptr)
+ , mKeyCode(0)
+ , mCharCode(0)
+ , mPseudoCharCode(0)
+ , mLocation(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD)
+ , mAccessKeyForwardedToChild(false)
+ , mUniqueId(0)
+#ifdef XP_MACOSX
+ , mNativeModifierFlags(0)
+ , mNativeKeyCode(0)
+#endif // #ifdef XP_MACOSX
+ , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
+ , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
+ , mInputMethodAppState(eNotHandled)
+ , mIsChar(false)
+ , mIsRepeat(false)
+ , mIsComposing(false)
+ , mIsReserved(false)
+ , mIsSynthesizedByTIP(false)
+ {
+ // If this is a keyboard event on a plugin, it shouldn't fired on content.
+ mFlags.mOnlySystemGroupDispatchInContent =
+ mFlags.mNoCrossProcessBoundaryForwarding = IsKeyEventOnPlugin();
+ }
+
+ static bool IsKeyDownOrKeyDownOnPlugin(EventMessage aMessage)
+ {
+ return aMessage == eKeyDown || aMessage == eKeyDownOnPlugin;
+ }
+ bool IsKeyDownOrKeyDownOnPlugin() const
+ {
+ return IsKeyDownOrKeyDownOnPlugin(mMessage);
+ }
+ static bool IsKeyUpOrKeyUpOnPlugin(EventMessage aMessage)
+ {
+ return aMessage == eKeyUp || aMessage == eKeyUpOnPlugin;
+ }
+ bool IsKeyUpOrKeyUpOnPlugin() const
+ {
+ return IsKeyUpOrKeyUpOnPlugin(mMessage);
+ }
+ static bool IsKeyEventOnPlugin(EventMessage aMessage)
+ {
+ return aMessage == eKeyDownOnPlugin || aMessage == eKeyUpOnPlugin;
+ }
+ bool IsKeyEventOnPlugin() const
+ {
+ return IsKeyEventOnPlugin(mMessage);
+ }
+
+ virtual WidgetEvent* Duplicate() const override
+ {
+ MOZ_ASSERT(mClass == eKeyboardEventClass,
+ "Duplicate() must be overridden by sub class");
+ // Not copying widget, it is a weak reference.
+ WidgetKeyboardEvent* result =
+ new WidgetKeyboardEvent(false, mMessage, nullptr);
+ result->AssignKeyEventData(*this, true);
+ result->mFlags = mFlags;
+ return result;
+ }
+
+ // OS translated Unicode chars which are used for accesskey and accelkey
+ // handling. The handlers will try from first character to last character.
+ nsTArray<AlternativeCharCode> mAlternativeCharCodes;
+ // DOM KeyboardEvent.key only when mKeyNameIndex is KEY_NAME_INDEX_USE_STRING.
+ nsString mKeyValue;
+ // DOM KeyboardEvent.code only when mCodeNameIndex is
+ // CODE_NAME_INDEX_USE_STRING.
+ nsString mCodeValue;
+
+#ifdef XP_MACOSX
+ // Values given by a native NSEvent, for use with Cocoa NPAPI plugins.
+ nsString mNativeCharacters;
+ nsString mNativeCharactersIgnoringModifiers;
+ // If this is non-empty, create a text event for plugins instead of a
+ // keyboard event.
+ nsString mPluginTextEventString;
+#endif // #ifdef XP_MACOSX
+
+ // OS-specific native event can optionally be preserved
+ void* mNativeKeyEvent;
+ // A DOM keyCode value or 0. If a keypress event whose mCharCode is 0, this
+ // should be 0.
+ uint32_t mKeyCode;
+ // If the instance is a keypress event of a printable key, this is a UTF-16
+ // value of the key. Otherwise, 0. This value must not be a control
+ // character when some modifiers are active. Then, this value should be an
+ // unmodified value except Shift and AltGr.
+ uint32_t mCharCode;
+ // mPseudoCharCode is valid only when mMessage is an eKeyDown event.
+ // This stores mCharCode value of keypress event which is fired with same
+ // key value and same modifier state.
+ uint32_t mPseudoCharCode;
+ // One of nsIDOMKeyEvent::DOM_KEY_LOCATION_*
+ uint32_t mLocation;
+ // True if accesskey handling was forwarded to the child via
+ // TabParent::HandleAccessKey. In this case, parent process menu access key
+ // handling should be delayed until it is determined that there exists no
+ // overriding access key in the content process.
+ bool mAccessKeyForwardedToChild;
+ // Unique id associated with a keydown / keypress event. Used in identifing
+ // keypress events for removal from async event dispatch queue in metrofx
+ // after preventDefault is called on keydown events. It's ok if this wraps
+ // over long periods.
+ uint32_t mUniqueId;
+
+#ifdef XP_MACOSX
+ // Values given by a native NSEvent, for use with Cocoa NPAPI plugins.
+ uint32_t mNativeModifierFlags;
+ uint16_t mNativeKeyCode;
+#endif // #ifdef XP_MACOSX
+
+ // DOM KeyboardEvent.key
+ KeyNameIndex mKeyNameIndex;
+ // DOM KeyboardEvent.code
+ CodeNameIndex mCodeNameIndex;
+ // Indicates that the event is being handled by input method app
+ typedef uint8_t InputMethodAppStateType;
+ enum InputMethodAppState : InputMethodAppStateType
+ {
+ eNotHandled, // not yet handled by intput method app
+ eHandling, // being handled by intput method app
+ eHandled // handled by input method app
+ };
+ InputMethodAppState mInputMethodAppState;
+
+ // Indicates whether the event signifies a printable character
+ bool mIsChar;
+ // Indicates whether the event is generated by auto repeat or not.
+ // if this is keyup event, always false.
+ bool mIsRepeat;
+ // Indicates whether the event is generated during IME (or deadkey)
+ // composition. This is initialized by EventStateManager. So, key event
+ // dispatchers don't need to initialize this.
+ bool mIsComposing;
+ // Indicates if the key combination is reserved by chrome. This is set by
+ // nsXBLWindowKeyHandler at capturing phase of the default event group.
+ bool mIsReserved;
+ // Indicates whether the event is synthesized from Text Input Processor
+ // or an actual event from nsAppShell.
+ bool mIsSynthesizedByTIP;
+
+ // If the key should cause keypress events, this returns true.
+ // Otherwise, false.
+ bool ShouldCauseKeypressEvents() const;
+
+ // mCharCode value of non-eKeyPress events is always 0. However, if
+ // non-eKeyPress event has one or more alternative char code values,
+ // its first item should be the mCharCode value of following eKeyPress event.
+ // PseudoCharCode() returns mCharCode value for eKeyPress event,
+ // the first alternative char code value of non-eKeyPress event or 0.
+ uint32_t PseudoCharCode() const
+ {
+ return mMessage == eKeyPress ? mCharCode : mPseudoCharCode;
+ }
+ void SetCharCode(uint32_t aCharCode)
+ {
+ if (mMessage == eKeyPress) {
+ mCharCode = aCharCode;
+ } else {
+ mPseudoCharCode = aCharCode;
+ }
+ }
+
+ void GetDOMKeyName(nsAString& aKeyName)
+ {
+ if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
+ aKeyName = mKeyValue;
+ return;
+ }
+ GetDOMKeyName(mKeyNameIndex, aKeyName);
+ }
+ void GetDOMCodeName(nsAString& aCodeName)
+ {
+ if (mCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
+ aCodeName = mCodeValue;
+ return;
+ }
+ GetDOMCodeName(mCodeNameIndex, aCodeName);
+ }
+
+ bool IsModifierKeyEvent() const
+ {
+ return GetModifierForKeyName(mKeyNameIndex) != MODIFIER_NONE;
+ }
+
+ /**
+ * Get the candidates for shortcut key.
+ *
+ * @param aCandidates [out] the candidate shortcut key combination list.
+ * the first item is most preferred.
+ */
+ void GetShortcutKeyCandidates(ShortcutKeyCandidateArray& aCandidates);
+
+ /**
+ * Get the candidates for access key.
+ *
+ * @param aCandidates [out] the candidate access key list.
+ * the first item is most preferred.
+ */
+ void GetAccessKeyCandidates(nsTArray<uint32_t>& aCandidates);
+
+ static void Shutdown();
+
+ /**
+ * ComputeLocationFromCodeValue() returns one of .mLocation value
+ * (nsIDOMKeyEvent::DOM_KEY_LOCATION_*) which is the most preferred value
+ * for the specified specified code value.
+ */
+ static uint32_t ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex);
+
+ /**
+ * ComputeKeyCodeFromKeyNameIndex() return a .mKeyCode value which can be
+ * mapped from the specified key value. Note that this returns 0 if the
+ * key name index is KEY_NAME_INDEX_Unidentified or KEY_NAME_INDEX_USE_STRING.
+ * This means that this method is useful only for non-printable keys.
+ */
+ static uint32_t ComputeKeyCodeFromKeyNameIndex(KeyNameIndex aKeyNameIndex);
+
+ /**
+ * GetModifierForKeyName() returns a value of Modifier which is activated
+ * by the aKeyNameIndex.
+ */
+ static Modifier GetModifierForKeyName(KeyNameIndex aKeyNameIndex);
+
+ /**
+ * IsLockableModifier() returns true if aKeyNameIndex is a lockable modifier
+ * key such as CapsLock and NumLock.
+ */
+ static bool IsLockableModifier(KeyNameIndex aKeyNameIndex);
+
+ static void GetDOMKeyName(KeyNameIndex aKeyNameIndex,
+ nsAString& aKeyName);
+ static void GetDOMCodeName(CodeNameIndex aCodeNameIndex,
+ nsAString& aCodeName);
+
+ static KeyNameIndex GetKeyNameIndex(const nsAString& aKeyValue);
+ static CodeNameIndex GetCodeNameIndex(const nsAString& aCodeValue);
+
+ static const char* GetCommandStr(Command aCommand);
+
+ void AssignKeyEventData(const WidgetKeyboardEvent& aEvent, bool aCopyTargets)
+ {
+ AssignInputEventData(aEvent, aCopyTargets);
+
+ mKeyCode = aEvent.mKeyCode;
+ mCharCode = aEvent.mCharCode;
+ mPseudoCharCode = aEvent.mPseudoCharCode;
+ mLocation = aEvent.mLocation;
+ mAlternativeCharCodes = aEvent.mAlternativeCharCodes;
+ mIsChar = aEvent.mIsChar;
+ mIsRepeat = aEvent.mIsRepeat;
+ mIsComposing = aEvent.mIsComposing;
+ mIsReserved = aEvent.mIsReserved;
+ mAccessKeyForwardedToChild = aEvent.mAccessKeyForwardedToChild;
+ mKeyNameIndex = aEvent.mKeyNameIndex;
+ mCodeNameIndex = aEvent.mCodeNameIndex;
+ mKeyValue = aEvent.mKeyValue;
+ mCodeValue = aEvent.mCodeValue;
+ // Don't copy mNativeKeyEvent because it may be referred after its instance
+ // is destroyed.
+ mNativeKeyEvent = nullptr;
+ mUniqueId = aEvent.mUniqueId;
+#ifdef XP_MACOSX
+ mNativeKeyCode = aEvent.mNativeKeyCode;
+ mNativeModifierFlags = aEvent.mNativeModifierFlags;
+ mNativeCharacters.Assign(aEvent.mNativeCharacters);
+ mNativeCharactersIgnoringModifiers.
+ Assign(aEvent.mNativeCharactersIgnoringModifiers);
+ mPluginTextEventString.Assign(aEvent.mPluginTextEventString);
+#endif
+ mInputMethodAppState = aEvent.mInputMethodAppState;
+ mIsSynthesizedByTIP = aEvent.mIsSynthesizedByTIP;
+ }
+
+private:
+ static const char16_t* const kKeyNames[];
+ static const char16_t* const kCodeNames[];
+ typedef nsDataHashtable<nsStringHashKey,
+ KeyNameIndex> KeyNameIndexHashtable;
+ typedef nsDataHashtable<nsStringHashKey,
+ CodeNameIndex> CodeNameIndexHashtable;
+ static KeyNameIndexHashtable* sKeyNameIndexHashtable;
+ static CodeNameIndexHashtable* sCodeNameIndexHashtable;
+};
+
+
+/******************************************************************************
+ * mozilla::InternalBeforeAfterKeyboardEvent
+ *
+ * This is extended from WidgetKeyboardEvent and is mapped to DOM event
+ * "BeforeAfterKeyboardEvent".
+ *
+ * Event mMessage: eBeforeKeyDown
+ * eBeforeKeyUp
+ * eAfterKeyDown
+ * eAfterKeyUp
+ ******************************************************************************/
+class InternalBeforeAfterKeyboardEvent : public WidgetKeyboardEvent
+{
+private:
+ friend class dom::PBrowserParent;
+ friend class dom::PBrowserChild;
+
+ InternalBeforeAfterKeyboardEvent()
+ {
+ }
+
+public:
+ // Extra member for InternalBeforeAfterKeyboardEvent. Indicates whether
+ // default actions of keydown/keyup event is prevented.
+ Nullable<bool> mEmbeddedCancelled;
+
+ virtual InternalBeforeAfterKeyboardEvent* AsBeforeAfterKeyboardEvent() override
+ {
+ return this;
+ }
+
+ InternalBeforeAfterKeyboardEvent(bool aIsTrusted, EventMessage aMessage,
+ nsIWidget* aWidget)
+ : WidgetKeyboardEvent(aIsTrusted, aMessage, aWidget,
+ eBeforeAfterKeyboardEventClass)
+ {
+ }
+
+ virtual WidgetEvent* Duplicate() const override
+ {
+ MOZ_ASSERT(mClass == eBeforeAfterKeyboardEventClass,
+ "Duplicate() must be overridden by sub class");
+ // Not copying widget, it is a weak reference.
+ InternalBeforeAfterKeyboardEvent* result =
+ new InternalBeforeAfterKeyboardEvent(false, mMessage, nullptr);
+ result->AssignBeforeAfterKeyEventData(*this, true);
+ result->mFlags = mFlags;
+ return result;
+ }
+
+ void AssignBeforeAfterKeyEventData(
+ const InternalBeforeAfterKeyboardEvent& aEvent,
+ bool aCopyTargets)
+ {
+ AssignKeyEventData(aEvent, aCopyTargets);
+ mEmbeddedCancelled = aEvent.mEmbeddedCancelled;
+ }
+
+ void AssignBeforeAfterKeyEventData(
+ const WidgetKeyboardEvent& aEvent,
+ bool aCopyTargets)
+ {
+ AssignKeyEventData(aEvent, aCopyTargets);
+ }
+};
+
+/******************************************************************************
+ * mozilla::WidgetCompositionEvent
+ ******************************************************************************/
+
+class WidgetCompositionEvent : public WidgetGUIEvent
+{
+private:
+ friend class mozilla::dom::PBrowserParent;
+ friend class mozilla::dom::PBrowserChild;
+
+ WidgetCompositionEvent()
+ {
+ }
+
+public:
+ virtual WidgetCompositionEvent* AsCompositionEvent() override
+ {
+ return this;
+ }
+
+ WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage,
+ nsIWidget* aWidget)
+ : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass)
+ , mNativeIMEContext(aWidget)
+ , mOriginalMessage(eVoidEvent)
+ {
+ }
+
+ virtual WidgetEvent* Duplicate() const override
+ {
+ MOZ_ASSERT(mClass == eCompositionEventClass,
+ "Duplicate() must be overridden by sub class");
+ // Not copying widget, it is a weak reference.
+ WidgetCompositionEvent* result =
+ new WidgetCompositionEvent(false, mMessage, nullptr);
+ result->AssignCompositionEventData(*this, true);
+ result->mFlags = mFlags;
+ return result;
+ }
+
+ // The composition string or the commit string. If the instance is a
+ // compositionstart event, this is initialized with selected text by
+ // TextComposition automatically.
+ nsString mData;
+
+ RefPtr<TextRangeArray> mRanges;
+
+ // mNativeIMEContext stores the native IME context which causes the
+ // composition event.
+ widget::NativeIMEContext mNativeIMEContext;
+
+ // If the instance is a clone of another event, mOriginalMessage stores
+ // the another event's mMessage.
+ EventMessage mOriginalMessage;
+
+ void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
+ bool aCopyTargets)
+ {
+ AssignGUIEventData(aEvent, aCopyTargets);
+
+ mData = aEvent.mData;
+ mOriginalMessage = aEvent.mOriginalMessage;
+ mRanges = aEvent.mRanges;
+
+ // Currently, we don't need to copy the other members because they are
+ // for internal use only (not available from JS).
+ }
+
+ bool IsComposing() const
+ {
+ return mRanges && mRanges->IsComposing();
+ }
+
+ uint32_t TargetClauseOffset() const
+ {
+ return mRanges ? mRanges->TargetClauseOffset() : 0;
+ }
+
+ uint32_t TargetClauseLength() const
+ {
+ uint32_t length = UINT32_MAX;
+ if (mRanges) {
+ length = mRanges->TargetClauseLength();
+ }
+ return length == UINT32_MAX ? mData.Length() : length;
+ }
+
+ uint32_t RangeCount() const
+ {
+ return mRanges ? mRanges->Length() : 0;
+ }
+
+ bool CausesDOMTextEvent() const
+ {
+ return mMessage == eCompositionChange ||
+ mMessage == eCompositionCommit ||
+ mMessage == eCompositionCommitAsIs;
+ }
+
+ bool CausesDOMCompositionEndEvent() const
+ {
+ return mMessage == eCompositionEnd ||
+ mMessage == eCompositionCommit ||
+ mMessage == eCompositionCommitAsIs;
+ }
+
+ bool IsFollowedByCompositionEnd() const
+ {
+ return IsFollowedByCompositionEnd(mOriginalMessage);
+ }
+
+ static bool IsFollowedByCompositionEnd(EventMessage aEventMessage)
+ {
+ return aEventMessage == eCompositionCommit ||
+ aEventMessage == eCompositionCommitAsIs;
+ }
+};
+
+/******************************************************************************
+ * mozilla::WidgetQueryContentEvent
+ ******************************************************************************/
+
+class WidgetQueryContentEvent : public WidgetGUIEvent
+{
+private:
+ friend class dom::PBrowserParent;
+ friend class dom::PBrowserChild;
+
+ WidgetQueryContentEvent()
+ : mSucceeded(false)
+ , mUseNativeLineBreak(true)
+ , mWithFontRanges(false)
+ {
+ MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
+ }
+
+public:
+ virtual WidgetQueryContentEvent* AsQueryContentEvent() override
+ {
+ return this;
+ }
+
+ WidgetQueryContentEvent(bool aIsTrusted, EventMessage aMessage,
+ nsIWidget* aWidget)
+ : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eQueryContentEventClass)
+ , mSucceeded(false)
+ , mUseNativeLineBreak(true)
+ , mWithFontRanges(false)
+ {
+ }
+
+ WidgetQueryContentEvent(EventMessage aMessage,
+ const WidgetQueryContentEvent& aOtherEvent)
+ : WidgetGUIEvent(aOtherEvent.IsTrusted(), aMessage,
+ const_cast<nsIWidget*>(aOtherEvent.mWidget.get()),
+ eQueryContentEventClass)
+ , mSucceeded(false)
+ , mUseNativeLineBreak(aOtherEvent.mUseNativeLineBreak)
+ , mWithFontRanges(false)
+ {
+ }
+
+ virtual WidgetEvent* Duplicate() const override
+ {
+ // This event isn't an internal event of any DOM event.
+ NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
+ "WidgetQueryContentEvent needs to support Duplicate()");
+ MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
+ }
+
+ struct Options final
+ {
+ bool mUseNativeLineBreak;
+ bool mRelativeToInsertionPoint;
+
+ explicit Options()
+ : mUseNativeLineBreak(true)
+ , mRelativeToInsertionPoint(false)
+ {
+ }
+
+ explicit Options(const WidgetQueryContentEvent& aEvent)
+ : mUseNativeLineBreak(aEvent.mUseNativeLineBreak)
+ , mRelativeToInsertionPoint(aEvent.mInput.mRelativeToInsertionPoint)
+ {
+ }
+ };
+
+ void Init(const Options& aOptions)
+ {
+ mUseNativeLineBreak = aOptions.mUseNativeLineBreak;
+ mInput.mRelativeToInsertionPoint = aOptions.mRelativeToInsertionPoint;
+ MOZ_ASSERT(mInput.IsValidEventMessage(mMessage));
+ }
+
+ void InitForQueryTextContent(int64_t aOffset, uint32_t aLength,
+ const Options& aOptions = Options())
+ {
+ NS_ASSERTION(mMessage == eQueryTextContent,
+ "wrong initializer is called");
+ mInput.mOffset = aOffset;
+ mInput.mLength = aLength;
+ Init(aOptions);
+ MOZ_ASSERT(mInput.IsValidOffset());
+ }
+
+ void InitForQueryCaretRect(int64_t aOffset,
+ const Options& aOptions = Options())
+ {
+ NS_ASSERTION(mMessage == eQueryCaretRect,
+ "wrong initializer is called");
+ mInput.mOffset = aOffset;
+ Init(aOptions);
+ MOZ_ASSERT(mInput.IsValidOffset());
+ }
+
+ void InitForQueryTextRect(int64_t aOffset, uint32_t aLength,
+ const Options& aOptions = Options())
+ {
+ NS_ASSERTION(mMessage == eQueryTextRect,
+ "wrong initializer is called");
+ mInput.mOffset = aOffset;
+ mInput.mLength = aLength;
+ Init(aOptions);
+ MOZ_ASSERT(mInput.IsValidOffset());
+ }
+
+ void InitForQuerySelectedText(SelectionType aSelectionType,
+ const Options& aOptions = Options())
+ {
+ MOZ_ASSERT(mMessage == eQuerySelectedText);
+ MOZ_ASSERT(aSelectionType != SelectionType::eNone);
+ mInput.mSelectionType = aSelectionType;
+ Init(aOptions);
+ }
+
+ void InitForQueryDOMWidgetHittest(const mozilla::LayoutDeviceIntPoint& aPoint)
+ {
+ NS_ASSERTION(mMessage == eQueryDOMWidgetHittest,
+ "wrong initializer is called");
+ mRefPoint = aPoint;
+ }
+
+ void InitForQueryTextRectArray(uint32_t aOffset, uint32_t aLength,
+ const Options& aOptions = Options())
+ {
+ NS_ASSERTION(mMessage == eQueryTextRectArray,
+ "wrong initializer is called");
+ mInput.mOffset = aOffset;
+ mInput.mLength = aLength;
+ Init(aOptions);
+ }
+
+ void RequestFontRanges()
+ {
+ NS_ASSERTION(mMessage == eQueryTextContent,
+ "not querying text content");
+ mWithFontRanges = true;
+ }
+
+ uint32_t GetSelectionStart(void) const
+ {
+ NS_ASSERTION(mMessage == eQuerySelectedText,
+ "not querying selection");
+ return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0);
+ }
+
+ uint32_t GetSelectionEnd(void) const
+ {
+ NS_ASSERTION(mMessage == eQuerySelectedText,
+ "not querying selection");
+ return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length());
+ }
+
+ mozilla::WritingMode GetWritingMode(void) const
+ {
+ NS_ASSERTION(mMessage == eQuerySelectedText ||
+ mMessage == eQueryCaretRect ||
+ mMessage == eQueryTextRect,
+ "not querying selection or text rect");
+ return mReply.mWritingMode;
+ }
+
+ bool mSucceeded;
+ bool mUseNativeLineBreak;
+ bool mWithFontRanges;
+ struct Input final
+ {
+ uint32_t EndOffset() const
+ {
+ CheckedInt<uint32_t> endOffset =
+ CheckedInt<uint32_t>(mOffset) + mLength;
+ return NS_WARN_IF(!endOffset.isValid()) ? UINT32_MAX : endOffset.value();
+ }
+
+ int64_t mOffset;
+ uint32_t mLength;
+ SelectionType mSelectionType;
+ // If mOffset is true, mOffset is relative to the start offset of
+ // composition if there is, otherwise, the start of the first selection
+ // range.
+ bool mRelativeToInsertionPoint;
+
+ Input()
+ : mOffset(0)
+ , mLength(0)
+ , mSelectionType(SelectionType::eNormal)
+ , mRelativeToInsertionPoint(false)
+ {
+ }
+
+ bool IsValidOffset() const
+ {
+ return mRelativeToInsertionPoint || mOffset >= 0;
+ }
+ bool IsValidEventMessage(EventMessage aEventMessage) const
+ {
+ if (!mRelativeToInsertionPoint) {
+ return true;
+ }
+ switch (aEventMessage) {
+ case eQueryTextContent:
+ case eQueryCaretRect:
+ case eQueryTextRect:
+ return true;
+ default:
+ return false;
+ }
+ }
+ bool MakeOffsetAbsolute(uint32_t aInsertionPointOffset)
+ {
+ if (NS_WARN_IF(!mRelativeToInsertionPoint)) {
+ return true;
+ }
+ mRelativeToInsertionPoint = false;
+ // If mOffset + aInsertionPointOffset becomes negative value,
+ // we should assume the absolute offset is 0.
+ if (mOffset < 0 && -mOffset > aInsertionPointOffset) {
+ mOffset = 0;
+ return true;
+ }
+ // Otherwise, we don't allow too large offset.
+ CheckedInt<uint32_t> absOffset = mOffset + aInsertionPointOffset;
+ if (NS_WARN_IF(!absOffset.isValid())) {
+ mOffset = UINT32_MAX;
+ return false;
+ }
+ mOffset = absOffset.value();
+ return true;
+ }
+ } mInput;
+
+ struct Reply final
+ {
+ void* mContentsRoot;
+ uint32_t mOffset;
+ // mTentativeCaretOffset is used by only eQueryCharacterAtPoint.
+ // This is the offset where caret would be if user clicked at the mRefPoint.
+ uint32_t mTentativeCaretOffset;
+ nsString mString;
+ // mRect is used by eQueryTextRect, eQueryCaretRect, eQueryCharacterAtPoint
+ // and eQueryEditorRect. The coordinates is system coordinates relative to
+ // the top level widget of mFocusedWidget. E.g., if a <xul:panel> which
+ // is owned by a window has focused editor, the offset of mRect is relative
+ // to the owner window, not the <xul:panel>.
+ mozilla::LayoutDeviceIntRect mRect;
+ // The return widget has the caret. This is set at all query events.
+ nsIWidget* mFocusedWidget;
+ // mozilla::WritingMode value at the end (focus) of the selection
+ mozilla::WritingMode mWritingMode;
+ // Used by eQuerySelectionAsTransferable
+ nsCOMPtr<nsITransferable> mTransferable;
+ // Used by eQueryTextContent with font ranges requested
+ AutoTArray<mozilla::FontRange, 1> mFontRanges;
+ // Used by eQueryTextRectArray
+ nsTArray<mozilla::LayoutDeviceIntRect> mRectArray;
+ // true if selection is reversed (end < start)
+ bool mReversed;
+ // true if the selection exists
+ bool mHasSelection;
+ // true if DOM element under mouse belongs to widget
+ bool mWidgetIsHit;
+
+ Reply()
+ : mContentsRoot(nullptr)
+ , mOffset(NOT_FOUND)
+ , mTentativeCaretOffset(NOT_FOUND)
+ , mFocusedWidget(nullptr)
+ , mReversed(false)
+ , mHasSelection(false)
+ , mWidgetIsHit(false)
+ {
+ }
+ } mReply;
+
+ enum
+ {
+ NOT_FOUND = UINT32_MAX
+ };
+
+ // values of mComputedScrollAction
+ enum
+ {
+ SCROLL_ACTION_NONE,
+ SCROLL_ACTION_LINE,
+ SCROLL_ACTION_PAGE
+ };
+};
+
+/******************************************************************************
+ * mozilla::WidgetSelectionEvent
+ ******************************************************************************/
+
+class WidgetSelectionEvent : public WidgetGUIEvent
+{
+private:
+ friend class mozilla::dom::PBrowserParent;
+ friend class mozilla::dom::PBrowserChild;
+
+ WidgetSelectionEvent()
+ : mOffset(0)
+ , mLength(0)
+ , mReversed(false)
+ , mExpandToClusterBoundary(true)
+ , mSucceeded(false)
+ , mUseNativeLineBreak(true)
+ {
+ }
+
+public:
+ virtual WidgetSelectionEvent* AsSelectionEvent() override
+ {
+ return this;
+ }
+
+ WidgetSelectionEvent(bool aIsTrusted, EventMessage aMessage,
+ nsIWidget* aWidget)
+ : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eSelectionEventClass)
+ , mOffset(0)
+ , mLength(0)
+ , mReversed(false)
+ , mExpandToClusterBoundary(true)
+ , mSucceeded(false)
+ , mUseNativeLineBreak(true)
+ , mReason(nsISelectionListener::NO_REASON)
+ {
+ }
+
+ virtual WidgetEvent* Duplicate() const override
+ {
+ // This event isn't an internal event of any DOM event.
+ NS_ASSERTION(!IsAllowedToDispatchDOMEvent(),
+ "WidgetSelectionEvent needs to support Duplicate()");
+ MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()");
+ return nullptr;
+ }
+
+ // Start offset of selection
+ uint32_t mOffset;
+ // Length of selection
+ uint32_t mLength;
+ // Selection "anchor" should be in front
+ bool mReversed;
+ // Cluster-based or character-based
+ bool mExpandToClusterBoundary;
+ // true if setting selection succeeded.
+ bool mSucceeded;
+ // true if native line breaks are used for mOffset and mLength
+ bool mUseNativeLineBreak;
+ // Fennec provides eSetSelection reason codes for downstream
+ // use in AccessibleCaret visibility logic.
+ int16_t mReason;
+};
+
+/******************************************************************************
+ * mozilla::InternalEditorInputEvent
+ ******************************************************************************/
+
+class InternalEditorInputEvent : public InternalUIEvent
+{
+private:
+ InternalEditorInputEvent()
+ : mIsComposing(false)
+ {
+ }
+
+public:
+ virtual InternalEditorInputEvent* AsEditorInputEvent() override
+ {
+ return this;
+ }
+
+ InternalEditorInputEvent(bool aIsTrusted, EventMessage aMessage,
+ nsIWidget* aWidget)
+ : InternalUIEvent(aIsTrusted, aMessage, aWidget, eEditorInputEventClass)
+ , mIsComposing(false)
+ {
+ }
+
+ virtual WidgetEvent* Duplicate() const override
+ {
+ MOZ_ASSERT(mClass == eEditorInputEventClass,
+ "Duplicate() must be overridden by sub class");
+ // Not copying widget, it is a weak reference.
+ InternalEditorInputEvent* result =
+ new InternalEditorInputEvent(false, mMessage, nullptr);
+ result->AssignEditorInputEventData(*this, true);
+ result->mFlags = mFlags;
+ return result;
+ }
+
+ bool mIsComposing;
+
+ void AssignEditorInputEventData(const InternalEditorInputEvent& aEvent,
+ bool aCopyTargets)
+ {
+ AssignUIEventData(aEvent, aCopyTargets);
+
+ mIsComposing = aEvent.mIsComposing;
+ }
+};
+
+} // namespace mozilla
+
+#endif // mozilla_TextEvents_h__