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 _AccEvent_H_ michael@0: #define _AccEvent_H_ michael@0: michael@0: #include "nsIAccessibleEvent.h" michael@0: michael@0: #include "mozilla/a11y/Accessible.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace dom { michael@0: class Selection; michael@0: } michael@0: michael@0: namespace a11y { michael@0: michael@0: class DocAccessible; michael@0: michael@0: // Constants used to point whether the event is from user input. michael@0: enum EIsFromUserInput michael@0: { michael@0: // eNoUserInput: event is not from user input michael@0: eNoUserInput = 0, michael@0: // eFromUserInput: event is from user input michael@0: eFromUserInput = 1, michael@0: // eAutoDetect: the value should be obtained from event state manager michael@0: eAutoDetect = -1 michael@0: }; michael@0: michael@0: /** michael@0: * Generic accessible event. michael@0: */ michael@0: class AccEvent michael@0: { michael@0: public: michael@0: michael@0: // Rule for accessible events. michael@0: // The rule will be applied when flushing pending events. michael@0: enum EEventRule { michael@0: // eAllowDupes : More than one event of the same type is allowed. michael@0: // This event will always be emitted. This flag is used for events that michael@0: // don't support coalescence. michael@0: eAllowDupes, michael@0: michael@0: // eCoalesceReorder : For reorder events from the same subtree or the same michael@0: // node, only the umbrella event on the ancestor will be emitted. michael@0: eCoalesceReorder, michael@0: michael@0: // eCoalesceMutationTextChange : coalesce text change events caused by michael@0: // tree mutations of the same tree level. michael@0: eCoalesceMutationTextChange, michael@0: michael@0: // eCoalesceOfSameType : For events of the same type, only the newest event michael@0: // will be processed. michael@0: eCoalesceOfSameType, michael@0: michael@0: // eCoalesceSelectionChange: coalescence of selection change events. michael@0: eCoalesceSelectionChange, michael@0: michael@0: // eCoalesceStateChange: coalesce state change events. michael@0: eCoalesceStateChange, michael@0: michael@0: // eCoalesceTextSelChange: coalescence of text selection change events. michael@0: eCoalesceTextSelChange, michael@0: michael@0: // eRemoveDupes : For repeat events, only the newest event in queue michael@0: // will be emitted. michael@0: eRemoveDupes, michael@0: michael@0: // eDoNotEmit : This event is confirmed as a duplicate, do not emit it. michael@0: eDoNotEmit michael@0: }; michael@0: michael@0: // Initialize with an nsIAccessible michael@0: AccEvent(uint32_t aEventType, Accessible* aAccessible, michael@0: EIsFromUserInput aIsFromUserInput = eAutoDetect, michael@0: EEventRule aEventRule = eRemoveDupes); michael@0: virtual ~AccEvent() {} michael@0: michael@0: // AccEvent michael@0: uint32_t GetEventType() const { return mEventType; } michael@0: EEventRule GetEventRule() const { return mEventRule; } michael@0: bool IsFromUserInput() const { return mIsFromUserInput; } michael@0: EIsFromUserInput FromUserInput() const michael@0: { return static_cast(mIsFromUserInput); } michael@0: michael@0: Accessible* GetAccessible() const { return mAccessible; } michael@0: DocAccessible* GetDocAccessible() const { return mAccessible->Document(); } michael@0: michael@0: /** michael@0: * Down casting. michael@0: */ michael@0: enum EventGroup { michael@0: eGenericEvent, michael@0: eStateChangeEvent, michael@0: eTextChangeEvent, michael@0: eMutationEvent, michael@0: eReorderEvent, michael@0: eHideEvent, michael@0: eShowEvent, michael@0: eCaretMoveEvent, michael@0: eTextSelChangeEvent, michael@0: eSelectionChangeEvent, michael@0: eTableChangeEvent, michael@0: eVirtualCursorChangeEvent michael@0: }; michael@0: michael@0: static const EventGroup kEventGroup = eGenericEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return 1U << eGenericEvent; michael@0: } michael@0: michael@0: /** michael@0: * Reference counting and cycle collection. michael@0: */ michael@0: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AccEvent) michael@0: NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent) michael@0: michael@0: protected: michael@0: bool mIsFromUserInput; michael@0: uint32_t mEventType; michael@0: EEventRule mEventRule; michael@0: nsRefPtr mAccessible; michael@0: michael@0: friend class EventQueue; michael@0: friend class AccReorderEvent; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible state change event. michael@0: */ michael@0: class AccStateChangeEvent: public AccEvent michael@0: { michael@0: public: michael@0: AccStateChangeEvent(Accessible* aAccessible, uint64_t aState, michael@0: bool aIsEnabled, michael@0: EIsFromUserInput aIsFromUserInput = eAutoDetect) : michael@0: AccEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible, michael@0: aIsFromUserInput, eCoalesceStateChange), michael@0: mState(aState), mIsEnabled(aIsEnabled) { } michael@0: michael@0: AccStateChangeEvent(Accessible* aAccessible, uint64_t aState) : michael@0: AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible, michael@0: eAutoDetect, eCoalesceStateChange), mState(aState) michael@0: { mIsEnabled = (mAccessible->State() & mState) != 0; } michael@0: michael@0: // AccEvent michael@0: static const EventGroup kEventGroup = eStateChangeEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eStateChangeEvent); michael@0: } michael@0: michael@0: // AccStateChangeEvent michael@0: uint64_t GetState() const { return mState; } michael@0: bool IsStateEnabled() const { return mIsEnabled; } michael@0: michael@0: private: michael@0: uint64_t mState; michael@0: bool mIsEnabled; michael@0: michael@0: friend class EventQueue; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible text change event. michael@0: */ michael@0: class AccTextChangeEvent: public AccEvent michael@0: { michael@0: public: michael@0: AccTextChangeEvent(Accessible* aAccessible, int32_t aStart, michael@0: const nsAString& aModifiedText, bool aIsInserted, michael@0: EIsFromUserInput aIsFromUserInput = eAutoDetect); michael@0: michael@0: // AccEvent michael@0: static const EventGroup kEventGroup = eTextChangeEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eTextChangeEvent); michael@0: } michael@0: michael@0: // AccTextChangeEvent michael@0: int32_t GetStartOffset() const { return mStart; } michael@0: uint32_t GetLength() const { return mModifiedText.Length(); } michael@0: bool IsTextInserted() const { return mIsInserted; } michael@0: void GetModifiedText(nsAString& aModifiedText) michael@0: { aModifiedText = mModifiedText; } michael@0: michael@0: private: michael@0: int32_t mStart; michael@0: bool mIsInserted; michael@0: nsString mModifiedText; michael@0: michael@0: friend class EventQueue; michael@0: friend class AccReorderEvent; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Base class for show and hide accessible events. michael@0: */ michael@0: class AccMutationEvent: public AccEvent michael@0: { michael@0: public: michael@0: AccMutationEvent(uint32_t aEventType, Accessible* aTarget, michael@0: nsINode* aTargetNode) : michael@0: AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceMutationTextChange) michael@0: { michael@0: // Don't coalesce these since they are coalesced by reorder event. Coalesce michael@0: // contained text change events. michael@0: mParent = mAccessible->Parent(); michael@0: } michael@0: virtual ~AccMutationEvent() { } michael@0: michael@0: // Event michael@0: static const EventGroup kEventGroup = eMutationEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eMutationEvent); michael@0: } michael@0: michael@0: // MutationEvent michael@0: bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; } michael@0: bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; } michael@0: michael@0: protected: michael@0: nsCOMPtr mNode; michael@0: nsRefPtr mParent; michael@0: nsRefPtr mTextChangeEvent; michael@0: michael@0: friend class EventQueue; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible hide event. michael@0: */ michael@0: class AccHideEvent: public AccMutationEvent michael@0: { michael@0: public: michael@0: AccHideEvent(Accessible* aTarget, nsINode* aTargetNode); michael@0: michael@0: // Event michael@0: static const EventGroup kEventGroup = eHideEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccMutationEvent::GetEventGroups() | (1U << eHideEvent); michael@0: } michael@0: michael@0: // AccHideEvent michael@0: Accessible* TargetParent() const { return mParent; } michael@0: Accessible* TargetNextSibling() const { return mNextSibling; } michael@0: Accessible* TargetPrevSibling() const { return mPrevSibling; } michael@0: michael@0: protected: michael@0: nsRefPtr mNextSibling; michael@0: nsRefPtr mPrevSibling; michael@0: michael@0: friend class EventQueue; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible show event. michael@0: */ michael@0: class AccShowEvent: public AccMutationEvent michael@0: { michael@0: public: michael@0: AccShowEvent(Accessible* aTarget, nsINode* aTargetNode); michael@0: michael@0: // Event michael@0: static const EventGroup kEventGroup = eShowEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccMutationEvent::GetEventGroups() | (1U << eShowEvent); michael@0: } michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Class for reorder accessible event. Takes care about michael@0: */ michael@0: class AccReorderEvent : public AccEvent michael@0: { michael@0: public: michael@0: AccReorderEvent(Accessible* aTarget) : michael@0: AccEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget, michael@0: eAutoDetect, eCoalesceReorder) { } michael@0: virtual ~AccReorderEvent() { } michael@0: michael@0: // Event michael@0: static const EventGroup kEventGroup = eReorderEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eReorderEvent); michael@0: } michael@0: michael@0: /** michael@0: * Get connected with mutation event. michael@0: */ michael@0: void AddSubMutationEvent(AccMutationEvent* aEvent) michael@0: { mDependentEvents.AppendElement(aEvent); } michael@0: michael@0: /** michael@0: * Do not emit the reorder event and its connected mutation events. michael@0: */ michael@0: void DoNotEmitAll() michael@0: { michael@0: mEventRule = AccEvent::eDoNotEmit; michael@0: uint32_t eventsCount = mDependentEvents.Length(); michael@0: for (uint32_t idx = 0; idx < eventsCount; idx++) michael@0: mDependentEvents[idx]->mEventRule = AccEvent::eDoNotEmit; michael@0: } michael@0: michael@0: /** michael@0: * Return true if the given accessible is a target of connected mutation michael@0: * event. michael@0: */ michael@0: uint32_t IsShowHideEventTarget(const Accessible* aTarget) const; michael@0: michael@0: protected: michael@0: /** michael@0: * Show and hide events causing this reorder event. michael@0: */ michael@0: nsTArray mDependentEvents; michael@0: michael@0: friend class EventQueue; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible caret move event. michael@0: */ michael@0: class AccCaretMoveEvent: public AccEvent michael@0: { michael@0: public: michael@0: AccCaretMoveEvent(Accessible* aAccessible, int32_t aCaretOffset, michael@0: EIsFromUserInput aIsFromUserInput = eAutoDetect) : michael@0: AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, michael@0: aIsFromUserInput), michael@0: mCaretOffset(aCaretOffset) { } michael@0: virtual ~AccCaretMoveEvent() { } michael@0: michael@0: // AccEvent michael@0: static const EventGroup kEventGroup = eCaretMoveEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eCaretMoveEvent); michael@0: } michael@0: michael@0: // AccCaretMoveEvent michael@0: int32_t GetCaretOffset() const { return mCaretOffset; } michael@0: michael@0: private: michael@0: int32_t mCaretOffset; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible text selection change event. michael@0: */ michael@0: class AccTextSelChangeEvent : public AccEvent michael@0: { michael@0: public: michael@0: AccTextSelChangeEvent(HyperTextAccessible* aTarget, michael@0: dom::Selection* aSelection, michael@0: int32_t aReason); michael@0: virtual ~AccTextSelChangeEvent(); michael@0: michael@0: // AccEvent michael@0: static const EventGroup kEventGroup = eTextSelChangeEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eTextSelChangeEvent); michael@0: } michael@0: michael@0: // AccTextSelChangeEvent michael@0: michael@0: /** michael@0: * Return true if the text selection change wasn't caused by pure caret move. michael@0: */ michael@0: bool IsCaretMoveOnly() const; michael@0: michael@0: private: michael@0: nsRefPtr mSel; michael@0: int32_t mReason; michael@0: michael@0: friend class EventQueue; michael@0: friend class SelectionManager; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible widget selection change event. michael@0: */ michael@0: class AccSelChangeEvent : public AccEvent michael@0: { michael@0: public: michael@0: enum SelChangeType { michael@0: eSelectionAdd, michael@0: eSelectionRemove michael@0: }; michael@0: michael@0: AccSelChangeEvent(Accessible* aWidget, Accessible* aItem, michael@0: SelChangeType aSelChangeType); michael@0: michael@0: virtual ~AccSelChangeEvent() { } michael@0: michael@0: // AccEvent michael@0: static const EventGroup kEventGroup = eSelectionChangeEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eSelectionChangeEvent); michael@0: } michael@0: michael@0: // AccSelChangeEvent michael@0: Accessible* Widget() const { return mWidget; } michael@0: michael@0: private: michael@0: nsRefPtr mWidget; michael@0: nsRefPtr mItem; michael@0: SelChangeType mSelChangeType; michael@0: uint32_t mPreceedingCount; michael@0: AccSelChangeEvent* mPackedEvent; michael@0: michael@0: friend class EventQueue; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Accessible table change event. michael@0: */ michael@0: class AccTableChangeEvent : public AccEvent michael@0: { michael@0: public: michael@0: AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType, michael@0: int32_t aRowOrColIndex, int32_t aNumRowsOrCols); michael@0: michael@0: // AccEvent michael@0: static const EventGroup kEventGroup = eTableChangeEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eTableChangeEvent); michael@0: } michael@0: michael@0: // AccTableChangeEvent michael@0: uint32_t GetIndex() const { return mRowOrColIndex; } michael@0: uint32_t GetCount() const { return mNumRowsOrCols; } michael@0: michael@0: private: michael@0: uint32_t mRowOrColIndex; // the start row/column after which the rows are inserted/deleted. michael@0: uint32_t mNumRowsOrCols; // the number of inserted/deleted rows/columns michael@0: }; michael@0: michael@0: /** michael@0: * Accessible virtual cursor change event. michael@0: */ michael@0: class AccVCChangeEvent : public AccEvent michael@0: { michael@0: public: michael@0: AccVCChangeEvent(Accessible* aAccessible, michael@0: nsIAccessible* aOldAccessible, michael@0: int32_t aOldStart, int32_t aOldEnd, michael@0: int16_t aReason); michael@0: michael@0: virtual ~AccVCChangeEvent() { } michael@0: michael@0: // AccEvent michael@0: static const EventGroup kEventGroup = eVirtualCursorChangeEvent; michael@0: virtual unsigned int GetEventGroups() const michael@0: { michael@0: return AccEvent::GetEventGroups() | (1U << eVirtualCursorChangeEvent); michael@0: } michael@0: michael@0: // AccTableChangeEvent michael@0: nsIAccessible* OldAccessible() const { return mOldAccessible; } michael@0: int32_t OldStartOffset() const { return mOldStart; } michael@0: int32_t OldEndOffset() const { return mOldEnd; } michael@0: int32_t Reason() const { return mReason; } michael@0: michael@0: private: michael@0: nsRefPtr mOldAccessible; michael@0: int32_t mOldStart; michael@0: int32_t mOldEnd; michael@0: int16_t mReason; michael@0: }; michael@0: michael@0: /** michael@0: * Downcast the generic accessible event object to derived type. michael@0: */ michael@0: class downcast_accEvent michael@0: { michael@0: public: michael@0: downcast_accEvent(AccEvent* e) : mRawPtr(e) { } michael@0: michael@0: template michael@0: operator Destination*() { michael@0: if (!mRawPtr) michael@0: return nullptr; michael@0: michael@0: return mRawPtr->GetEventGroups() & (1U << Destination::kEventGroup) ? michael@0: static_cast(mRawPtr) : nullptr; michael@0: } michael@0: michael@0: private: michael@0: AccEvent* mRawPtr; michael@0: }; michael@0: michael@0: /** michael@0: * Return a new xpcom accessible event for the given internal one. michael@0: */ michael@0: already_AddRefed michael@0: MakeXPCEvent(AccEvent* aEvent); michael@0: michael@0: } // namespace a11y michael@0: } // namespace mozilla michael@0: michael@0: #endif michael@0: