Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "AccEvent.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "nsAccUtils.h" |
michael@0 | 10 | #include "DocAccessible.h" |
michael@0 | 11 | #include "xpcAccEvents.h" |
michael@0 | 12 | #include "States.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "mozilla/EventStateManager.h" |
michael@0 | 15 | #include "mozilla/dom/Selection.h" |
michael@0 | 16 | |
michael@0 | 17 | using namespace mozilla; |
michael@0 | 18 | using namespace mozilla::a11y; |
michael@0 | 19 | |
michael@0 | 20 | static_assert(static_cast<bool>(eNoUserInput) == false && |
michael@0 | 21 | static_cast<bool>(eFromUserInput) == true, |
michael@0 | 22 | "EIsFromUserInput cannot be casted to bool"); |
michael@0 | 23 | |
michael@0 | 24 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 25 | // AccEvent |
michael@0 | 26 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 27 | |
michael@0 | 28 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 29 | // AccEvent constructors |
michael@0 | 30 | |
michael@0 | 31 | AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible, |
michael@0 | 32 | EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) : |
michael@0 | 33 | mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible) |
michael@0 | 34 | { |
michael@0 | 35 | if (aIsFromUserInput == eAutoDetect) |
michael@0 | 36 | mIsFromUserInput = EventStateManager::IsHandlingUserInput(); |
michael@0 | 37 | else |
michael@0 | 38 | mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false; |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 42 | // AccEvent cycle collection |
michael@0 | 43 | |
michael@0 | 44 | NS_IMPL_CYCLE_COLLECTION(AccEvent, mAccessible) |
michael@0 | 45 | |
michael@0 | 46 | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef) |
michael@0 | 47 | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release) |
michael@0 | 48 | |
michael@0 | 49 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 50 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 51 | // AccTextChangeEvent |
michael@0 | 52 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 53 | |
michael@0 | 54 | // Note: we pass in eAllowDupes to the base class because we don't support text |
michael@0 | 55 | // events coalescence. We fire delayed text change events in DocAccessible but |
michael@0 | 56 | // we continue to base the event off the accessible object rather than just the |
michael@0 | 57 | // node. This means we won't try to create an accessible based on the node when |
michael@0 | 58 | // we are ready to fire the event and so we will no longer assert at that point |
michael@0 | 59 | // if the node was removed from the document. Either way, the AT won't work with |
michael@0 | 60 | // a defunct accessible so the behaviour should be equivalent. |
michael@0 | 61 | AccTextChangeEvent:: |
michael@0 | 62 | AccTextChangeEvent(Accessible* aAccessible, int32_t aStart, |
michael@0 | 63 | const nsAString& aModifiedText, bool aIsInserted, |
michael@0 | 64 | EIsFromUserInput aIsFromUserInput) |
michael@0 | 65 | : AccEvent(aIsInserted ? |
michael@0 | 66 | static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_INSERTED) : |
michael@0 | 67 | static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_REMOVED), |
michael@0 | 68 | aAccessible, aIsFromUserInput, eAllowDupes) |
michael@0 | 69 | , mStart(aStart) |
michael@0 | 70 | , mIsInserted(aIsInserted) |
michael@0 | 71 | , mModifiedText(aModifiedText) |
michael@0 | 72 | { |
michael@0 | 73 | // XXX We should use IsFromUserInput here, but that isn't always correct |
michael@0 | 74 | // when the text change isn't related to content insertion or removal. |
michael@0 | 75 | mIsFromUserInput = mAccessible->State() & |
michael@0 | 76 | (states::FOCUSED | states::EDITABLE); |
michael@0 | 77 | } |
michael@0 | 78 | |
michael@0 | 79 | |
michael@0 | 80 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 81 | // AccReorderEvent |
michael@0 | 82 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 83 | |
michael@0 | 84 | uint32_t |
michael@0 | 85 | AccReorderEvent::IsShowHideEventTarget(const Accessible* aTarget) const |
michael@0 | 86 | { |
michael@0 | 87 | uint32_t count = mDependentEvents.Length(); |
michael@0 | 88 | for (uint32_t index = count - 1; index < count; index--) { |
michael@0 | 89 | if (mDependentEvents[index]->mAccessible == aTarget) { |
michael@0 | 90 | uint32_t eventType = mDependentEvents[index]->mEventType; |
michael@0 | 91 | if (eventType == nsIAccessibleEvent::EVENT_SHOW || |
michael@0 | 92 | eventType == nsIAccessibleEvent::EVENT_HIDE) { |
michael@0 | 93 | return mDependentEvents[index]->mEventType; |
michael@0 | 94 | } |
michael@0 | 95 | } |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | return 0; |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 102 | // AccHideEvent |
michael@0 | 103 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 104 | |
michael@0 | 105 | AccHideEvent:: |
michael@0 | 106 | AccHideEvent(Accessible* aTarget, nsINode* aTargetNode) : |
michael@0 | 107 | AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode) |
michael@0 | 108 | { |
michael@0 | 109 | mNextSibling = mAccessible->NextSibling(); |
michael@0 | 110 | mPrevSibling = mAccessible->PrevSibling(); |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | |
michael@0 | 114 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 115 | // AccShowEvent |
michael@0 | 116 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 117 | |
michael@0 | 118 | AccShowEvent:: |
michael@0 | 119 | AccShowEvent(Accessible* aTarget, nsINode* aTargetNode) : |
michael@0 | 120 | AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode) |
michael@0 | 121 | { |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | |
michael@0 | 125 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 126 | // AccTextSelChangeEvent |
michael@0 | 127 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 128 | |
michael@0 | 129 | AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget, |
michael@0 | 130 | dom::Selection* aSelection, |
michael@0 | 131 | int32_t aReason) : |
michael@0 | 132 | AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget, |
michael@0 | 133 | eAutoDetect, eCoalesceTextSelChange), |
michael@0 | 134 | mSel(aSelection), mReason(aReason) {} |
michael@0 | 135 | |
michael@0 | 136 | AccTextSelChangeEvent::~AccTextSelChangeEvent() { } |
michael@0 | 137 | |
michael@0 | 138 | bool |
michael@0 | 139 | AccTextSelChangeEvent::IsCaretMoveOnly() const |
michael@0 | 140 | { |
michael@0 | 141 | return mSel->GetRangeCount() == 1 && mSel->IsCollapsed() && |
michael@0 | 142 | ((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON | |
michael@0 | 143 | nsISelectionListener::COLLAPSETOEND_REASON)) == 0); |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 147 | // AccSelChangeEvent |
michael@0 | 148 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 149 | |
michael@0 | 150 | AccSelChangeEvent:: |
michael@0 | 151 | AccSelChangeEvent(Accessible* aWidget, Accessible* aItem, |
michael@0 | 152 | SelChangeType aSelChangeType) : |
michael@0 | 153 | AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange), |
michael@0 | 154 | mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType), |
michael@0 | 155 | mPreceedingCount(0), mPackedEvent(nullptr) |
michael@0 | 156 | { |
michael@0 | 157 | if (aSelChangeType == eSelectionAdd) { |
michael@0 | 158 | if (mWidget->GetSelectedItem(1)) |
michael@0 | 159 | mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; |
michael@0 | 160 | else |
michael@0 | 161 | mEventType = nsIAccessibleEvent::EVENT_SELECTION; |
michael@0 | 162 | } else { |
michael@0 | 163 | mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE; |
michael@0 | 164 | } |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | |
michael@0 | 168 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 169 | // AccTableChangeEvent |
michael@0 | 170 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 171 | |
michael@0 | 172 | AccTableChangeEvent:: |
michael@0 | 173 | AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType, |
michael@0 | 174 | int32_t aRowOrColIndex, int32_t aNumRowsOrCols) : |
michael@0 | 175 | AccEvent(aEventType, aAccessible), |
michael@0 | 176 | mRowOrColIndex(aRowOrColIndex), mNumRowsOrCols(aNumRowsOrCols) |
michael@0 | 177 | { |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | |
michael@0 | 181 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 182 | // AccVCChangeEvent |
michael@0 | 183 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 184 | |
michael@0 | 185 | AccVCChangeEvent:: |
michael@0 | 186 | AccVCChangeEvent(Accessible* aAccessible, |
michael@0 | 187 | nsIAccessible* aOldAccessible, |
michael@0 | 188 | int32_t aOldStart, int32_t aOldEnd, |
michael@0 | 189 | int16_t aReason) : |
michael@0 | 190 | AccEvent(::nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED, aAccessible), |
michael@0 | 191 | mOldAccessible(aOldAccessible), mOldStart(aOldStart), mOldEnd(aOldEnd), |
michael@0 | 192 | mReason(aReason) |
michael@0 | 193 | { |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | already_AddRefed<nsIAccessibleEvent> |
michael@0 | 197 | a11y::MakeXPCEvent(AccEvent* aEvent) |
michael@0 | 198 | { |
michael@0 | 199 | DocAccessible* doc = aEvent->GetDocAccessible(); |
michael@0 | 200 | Accessible* acc = aEvent->GetAccessible(); |
michael@0 | 201 | nsINode* node = acc->GetNode(); |
michael@0 | 202 | nsIDOMNode* domNode = node ? node->AsDOMNode() : nullptr; |
michael@0 | 203 | bool fromUser = aEvent->IsFromUserInput(); |
michael@0 | 204 | uint32_t type = aEvent->GetEventType(); |
michael@0 | 205 | uint32_t eventGroup = aEvent->GetEventGroups(); |
michael@0 | 206 | nsCOMPtr<nsIAccessibleEvent> xpEvent; |
michael@0 | 207 | |
michael@0 | 208 | if (eventGroup & (1 << AccEvent::eStateChangeEvent)) { |
michael@0 | 209 | AccStateChangeEvent* sc = downcast_accEvent(aEvent); |
michael@0 | 210 | bool extra = false; |
michael@0 | 211 | uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra); |
michael@0 | 212 | xpEvent = new xpcAccStateChangeEvent(type, acc, doc, domNode, fromUser, |
michael@0 | 213 | state, extra, sc->IsStateEnabled()); |
michael@0 | 214 | return xpEvent.forget(); |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | if (eventGroup & (1 << AccEvent::eTextChangeEvent)) { |
michael@0 | 218 | AccTextChangeEvent* tc = downcast_accEvent(aEvent); |
michael@0 | 219 | nsString text; |
michael@0 | 220 | tc->GetModifiedText(text); |
michael@0 | 221 | xpEvent = new xpcAccTextChangeEvent(type, acc, doc, domNode, fromUser, |
michael@0 | 222 | tc->GetStartOffset(), tc->GetLength(), |
michael@0 | 223 | tc->IsTextInserted(), text); |
michael@0 | 224 | return xpEvent.forget(); |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | if (eventGroup & (1 << AccEvent::eHideEvent)) { |
michael@0 | 228 | AccHideEvent* hideEvent = downcast_accEvent(aEvent); |
michael@0 | 229 | xpEvent = new xpcAccHideEvent(type, acc, doc, domNode, fromUser, |
michael@0 | 230 | hideEvent->TargetParent(), |
michael@0 | 231 | hideEvent->TargetNextSibling(), |
michael@0 | 232 | hideEvent->TargetPrevSibling()); |
michael@0 | 233 | return xpEvent.forget(); |
michael@0 | 234 | } |
michael@0 | 235 | |
michael@0 | 236 | if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) { |
michael@0 | 237 | AccCaretMoveEvent* cm = downcast_accEvent(aEvent); |
michael@0 | 238 | xpEvent = new xpcAccCaretMoveEvent(type, acc, doc, domNode, fromUser, |
michael@0 | 239 | cm->GetCaretOffset()); |
michael@0 | 240 | return xpEvent.forget(); |
michael@0 | 241 | } |
michael@0 | 242 | |
michael@0 | 243 | if (eventGroup & (1 << AccEvent::eVirtualCursorChangeEvent)) { |
michael@0 | 244 | AccVCChangeEvent* vcc = downcast_accEvent(aEvent); |
michael@0 | 245 | xpEvent = new xpcAccVirtualCursorChangeEvent(type, acc, doc, domNode, fromUser, |
michael@0 | 246 | vcc->OldAccessible(), |
michael@0 | 247 | vcc->OldStartOffset(), |
michael@0 | 248 | vcc->OldEndOffset(), |
michael@0 | 249 | vcc->Reason()); |
michael@0 | 250 | return xpEvent.forget(); |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | xpEvent = new xpcAccEvent(type, acc, doc, domNode, fromUser); |
michael@0 | 254 | return xpEvent.forget(); |
michael@0 | 255 | } |