michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ 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: #include "AccEvent.h" michael@0: michael@0: #include "nsAccUtils.h" michael@0: #include "DocAccessible.h" michael@0: #include "xpcAccEvents.h" michael@0: #include "States.h" michael@0: michael@0: #include "mozilla/EventStateManager.h" michael@0: #include "mozilla/dom/Selection.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: michael@0: static_assert(static_cast(eNoUserInput) == false && michael@0: static_cast(eFromUserInput) == true, michael@0: "EIsFromUserInput cannot be casted to bool"); michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccEvent constructors michael@0: michael@0: AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible, michael@0: EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) : michael@0: mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible) michael@0: { michael@0: if (aIsFromUserInput == eAutoDetect) michael@0: mIsFromUserInput = EventStateManager::IsHandlingUserInput(); michael@0: else michael@0: mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccEvent cycle collection michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION(AccEvent, mAccessible) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef) michael@0: NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccTextChangeEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: // Note: we pass in eAllowDupes to the base class because we don't support text michael@0: // events coalescence. We fire delayed text change events in DocAccessible but michael@0: // we continue to base the event off the accessible object rather than just the michael@0: // node. This means we won't try to create an accessible based on the node when michael@0: // we are ready to fire the event and so we will no longer assert at that point michael@0: // if the node was removed from the document. Either way, the AT won't work with michael@0: // a defunct accessible so the behaviour should be equivalent. michael@0: AccTextChangeEvent:: michael@0: AccTextChangeEvent(Accessible* aAccessible, int32_t aStart, michael@0: const nsAString& aModifiedText, bool aIsInserted, michael@0: EIsFromUserInput aIsFromUserInput) michael@0: : AccEvent(aIsInserted ? michael@0: static_cast(nsIAccessibleEvent::EVENT_TEXT_INSERTED) : michael@0: static_cast(nsIAccessibleEvent::EVENT_TEXT_REMOVED), michael@0: aAccessible, aIsFromUserInput, eAllowDupes) michael@0: , mStart(aStart) michael@0: , mIsInserted(aIsInserted) michael@0: , mModifiedText(aModifiedText) michael@0: { michael@0: // XXX We should use IsFromUserInput here, but that isn't always correct michael@0: // when the text change isn't related to content insertion or removal. michael@0: mIsFromUserInput = mAccessible->State() & michael@0: (states::FOCUSED | states::EDITABLE); michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccReorderEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: uint32_t michael@0: AccReorderEvent::IsShowHideEventTarget(const Accessible* aTarget) const michael@0: { michael@0: uint32_t count = mDependentEvents.Length(); michael@0: for (uint32_t index = count - 1; index < count; index--) { michael@0: if (mDependentEvents[index]->mAccessible == aTarget) { michael@0: uint32_t eventType = mDependentEvents[index]->mEventType; michael@0: if (eventType == nsIAccessibleEvent::EVENT_SHOW || michael@0: eventType == nsIAccessibleEvent::EVENT_HIDE) { michael@0: return mDependentEvents[index]->mEventType; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccHideEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: AccHideEvent:: michael@0: AccHideEvent(Accessible* aTarget, nsINode* aTargetNode) : michael@0: AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode) michael@0: { michael@0: mNextSibling = mAccessible->NextSibling(); michael@0: mPrevSibling = mAccessible->PrevSibling(); michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccShowEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: AccShowEvent:: michael@0: AccShowEvent(Accessible* aTarget, nsINode* aTargetNode) : michael@0: AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode) michael@0: { michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccTextSelChangeEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget, michael@0: dom::Selection* aSelection, michael@0: int32_t aReason) : michael@0: AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget, michael@0: eAutoDetect, eCoalesceTextSelChange), michael@0: mSel(aSelection), mReason(aReason) {} michael@0: michael@0: AccTextSelChangeEvent::~AccTextSelChangeEvent() { } michael@0: michael@0: bool michael@0: AccTextSelChangeEvent::IsCaretMoveOnly() const michael@0: { michael@0: return mSel->GetRangeCount() == 1 && mSel->IsCollapsed() && michael@0: ((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON | michael@0: nsISelectionListener::COLLAPSETOEND_REASON)) == 0); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccSelChangeEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: AccSelChangeEvent:: michael@0: AccSelChangeEvent(Accessible* aWidget, Accessible* aItem, michael@0: SelChangeType aSelChangeType) : michael@0: AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange), michael@0: mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType), michael@0: mPreceedingCount(0), mPackedEvent(nullptr) michael@0: { michael@0: if (aSelChangeType == eSelectionAdd) { michael@0: if (mWidget->GetSelectedItem(1)) michael@0: mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; michael@0: else michael@0: mEventType = nsIAccessibleEvent::EVENT_SELECTION; michael@0: } else { michael@0: mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE; michael@0: } michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccTableChangeEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: AccTableChangeEvent:: michael@0: AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType, michael@0: int32_t aRowOrColIndex, int32_t aNumRowsOrCols) : michael@0: AccEvent(aEventType, aAccessible), michael@0: mRowOrColIndex(aRowOrColIndex), mNumRowsOrCols(aNumRowsOrCols) michael@0: { michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // AccVCChangeEvent michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: AccVCChangeEvent:: michael@0: AccVCChangeEvent(Accessible* aAccessible, michael@0: nsIAccessible* aOldAccessible, michael@0: int32_t aOldStart, int32_t aOldEnd, michael@0: int16_t aReason) : michael@0: AccEvent(::nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED, aAccessible), michael@0: mOldAccessible(aOldAccessible), mOldStart(aOldStart), mOldEnd(aOldEnd), michael@0: mReason(aReason) michael@0: { michael@0: } michael@0: michael@0: already_AddRefed michael@0: a11y::MakeXPCEvent(AccEvent* aEvent) michael@0: { michael@0: DocAccessible* doc = aEvent->GetDocAccessible(); michael@0: Accessible* acc = aEvent->GetAccessible(); michael@0: nsINode* node = acc->GetNode(); michael@0: nsIDOMNode* domNode = node ? node->AsDOMNode() : nullptr; michael@0: bool fromUser = aEvent->IsFromUserInput(); michael@0: uint32_t type = aEvent->GetEventType(); michael@0: uint32_t eventGroup = aEvent->GetEventGroups(); michael@0: nsCOMPtr xpEvent; michael@0: michael@0: if (eventGroup & (1 << AccEvent::eStateChangeEvent)) { michael@0: AccStateChangeEvent* sc = downcast_accEvent(aEvent); michael@0: bool extra = false; michael@0: uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra); michael@0: xpEvent = new xpcAccStateChangeEvent(type, acc, doc, domNode, fromUser, michael@0: state, extra, sc->IsStateEnabled()); michael@0: return xpEvent.forget(); michael@0: } michael@0: michael@0: if (eventGroup & (1 << AccEvent::eTextChangeEvent)) { michael@0: AccTextChangeEvent* tc = downcast_accEvent(aEvent); michael@0: nsString text; michael@0: tc->GetModifiedText(text); michael@0: xpEvent = new xpcAccTextChangeEvent(type, acc, doc, domNode, fromUser, michael@0: tc->GetStartOffset(), tc->GetLength(), michael@0: tc->IsTextInserted(), text); michael@0: return xpEvent.forget(); michael@0: } michael@0: michael@0: if (eventGroup & (1 << AccEvent::eHideEvent)) { michael@0: AccHideEvent* hideEvent = downcast_accEvent(aEvent); michael@0: xpEvent = new xpcAccHideEvent(type, acc, doc, domNode, fromUser, michael@0: hideEvent->TargetParent(), michael@0: hideEvent->TargetNextSibling(), michael@0: hideEvent->TargetPrevSibling()); michael@0: return xpEvent.forget(); michael@0: } michael@0: michael@0: if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) { michael@0: AccCaretMoveEvent* cm = downcast_accEvent(aEvent); michael@0: xpEvent = new xpcAccCaretMoveEvent(type, acc, doc, domNode, fromUser, michael@0: cm->GetCaretOffset()); michael@0: return xpEvent.forget(); michael@0: } michael@0: michael@0: if (eventGroup & (1 << AccEvent::eVirtualCursorChangeEvent)) { michael@0: AccVCChangeEvent* vcc = downcast_accEvent(aEvent); michael@0: xpEvent = new xpcAccVirtualCursorChangeEvent(type, acc, doc, domNode, fromUser, michael@0: vcc->OldAccessible(), michael@0: vcc->OldStartOffset(), michael@0: vcc->OldEndOffset(), michael@0: vcc->Reason()); michael@0: return xpEvent.forget(); michael@0: } michael@0: michael@0: xpEvent = new xpcAccEvent(type, acc, doc, domNode, fromUser); michael@0: return xpEvent.forget(); michael@0: }