AccEvent.cpp (10504B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "AccEvent.h" 8 9 #include "nsAccUtils.h" 10 #include "xpcAccEvents.h" 11 #include "States.h" 12 #include "TextRange.h" 13 #include "xpcAccessibleDocument.h" 14 #include "xpcAccessibleTextRange.h" 15 16 #include "mozilla/dom/Selection.h" 17 #include "mozilla/dom/UserActivation.h" 18 19 #include "nsComponentManagerUtils.h" 20 #include "nsIMutableArray.h" 21 22 using namespace mozilla; 23 using namespace mozilla::a11y; 24 25 static_assert(static_cast<bool>(eNoUserInput) == false && 26 static_cast<bool>(eFromUserInput) == true, 27 "EIsFromUserInput cannot be casted to bool"); 28 29 //////////////////////////////////////////////////////////////////////////////// 30 // AccEvent 31 //////////////////////////////////////////////////////////////////////////////// 32 33 //////////////////////////////////////////////////////////////////////////////// 34 // AccEvent constructors 35 36 AccEvent::AccEvent(uint32_t aEventType, LocalAccessible* aAccessible, 37 EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) 38 : mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible) { 39 if (aIsFromUserInput == eAutoDetect) { 40 mIsFromUserInput = dom::UserActivation::IsHandlingUserInput(); 41 } else { 42 mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false; 43 } 44 } 45 46 //////////////////////////////////////////////////////////////////////////////// 47 // AccEvent cycle collection 48 49 NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent) 50 51 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent) 52 NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible) 53 if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) { 54 tmEvent->SetNextEvent(nullptr); 55 tmEvent->SetPrevEvent(nullptr); 56 } 57 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 58 59 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent) 60 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible) 61 if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) { 62 CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext"); 63 CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent"); 64 } 65 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 66 67 //////////////////////////////////////////////////////////////////////////////// 68 //////////////////////////////////////////////////////////////////////////////// 69 // AccTextChangeEvent 70 //////////////////////////////////////////////////////////////////////////////// 71 72 // Note: we pass in eAllowDupes to the base class because we don't support text 73 // events coalescence. We fire delayed text change events in DocAccessible but 74 // we continue to base the event off the accessible object rather than just the 75 // node. This means we won't try to create an accessible based on the node when 76 // we are ready to fire the event and so we will no longer assert at that point 77 // if the node was removed from the document. Either way, the AT won't work with 78 // a defunct accessible so the behaviour should be equivalent. 79 AccTextChangeEvent::AccTextChangeEvent(LocalAccessible* aAccessible, 80 int32_t aStart, 81 const nsAString& aModifiedText, 82 bool aIsInserted, 83 EIsFromUserInput aIsFromUserInput) 84 : AccEvent( 85 aIsInserted 86 ? static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_INSERTED) 87 : static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_REMOVED), 88 aAccessible, aIsFromUserInput, eAllowDupes), 89 mStart(aStart), 90 mIsInserted(aIsInserted), 91 mModifiedText(aModifiedText) { 92 // XXX We should use IsFromUserInput here, but that isn't always correct 93 // when the text change isn't related to content insertion or removal. 94 mIsFromUserInput = 95 mAccessible->State() & (states::FOCUSED | states::EDITABLE); 96 } 97 98 //////////////////////////////////////////////////////////////////////////////// 99 // AccHideEvent 100 //////////////////////////////////////////////////////////////////////////////// 101 102 AccHideEvent::AccHideEvent(LocalAccessible* aTarget, bool aNeedsShutdown) 103 : AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget), 104 mNeedsShutdown(aNeedsShutdown) { 105 mNextSibling = mAccessible->LocalNextSibling(); 106 mPrevSibling = mAccessible->LocalPrevSibling(); 107 } 108 109 //////////////////////////////////////////////////////////////////////////////// 110 // AccShowEvent 111 //////////////////////////////////////////////////////////////////////////////// 112 113 //////////////////////////////////////////////////////////////////////////////// 114 // AccTextSelChangeEvent 115 //////////////////////////////////////////////////////////////////////////////// 116 117 AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget, 118 dom::Selection* aSelection, 119 int32_t aReason, 120 int32_t aGranularity) 121 : AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget, 122 eAutoDetect, eCoalesceTextSelChange), 123 mSel(aSelection), 124 mReason(aReason), 125 mGranularity(aGranularity) {} 126 127 AccTextSelChangeEvent::~AccTextSelChangeEvent() {} 128 129 bool AccTextSelChangeEvent::IsCaretMoveOnly() const { 130 return mSel->RangeCount() == 1 && mSel->IsCollapsed() && 131 ((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON | 132 nsISelectionListener::COLLAPSETOEND_REASON)) == 0); 133 } 134 135 void AccTextSelChangeEvent::SelectionRanges( 136 nsTArray<TextRange>* aRanges) const { 137 TextRange::TextRangesFromSelection(mSel, aRanges); 138 } 139 140 //////////////////////////////////////////////////////////////////////////////// 141 // AccSelChangeEvent 142 //////////////////////////////////////////////////////////////////////////////// 143 144 AccSelChangeEvent::AccSelChangeEvent(LocalAccessible* aWidget, 145 LocalAccessible* aItem, 146 SelChangeType aSelChangeType) 147 : AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange), 148 mWidget(aWidget), 149 mItem(aItem), 150 mSelChangeType(aSelChangeType), 151 mPreceedingCount(0), 152 mPackedEvent(nullptr) { 153 if (aSelChangeType == eSelectionAdd) { 154 if (mWidget->GetSelectedItem(1)) { 155 mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; 156 } else { 157 mEventType = nsIAccessibleEvent::EVENT_SELECTION; 158 } 159 } else { 160 mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE; 161 } 162 } 163 164 already_AddRefed<nsIAccessibleEvent> a11y::MakeXPCEvent(AccEvent* aEvent) { 165 DocAccessible* doc = aEvent->Document(); 166 LocalAccessible* acc = aEvent->GetAccessible(); 167 nsINode* node = acc->GetNode(); 168 bool fromUser = aEvent->IsFromUserInput(); 169 uint32_t type = aEvent->GetEventType(); 170 uint32_t eventGroup = aEvent->GetEventGroups(); 171 nsCOMPtr<nsIAccessibleEvent> xpEvent; 172 173 if (eventGroup & (1 << AccEvent::eStateChangeEvent)) { 174 AccStateChangeEvent* sc = downcast_accEvent(aEvent); 175 bool extra = false; 176 uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra); 177 xpEvent = new xpcAccStateChangeEvent(type, ToXPC(acc), ToXPCDocument(doc), 178 node, fromUser, state, extra, 179 sc->IsStateEnabled()); 180 return xpEvent.forget(); 181 } 182 183 if (eventGroup & (1 << AccEvent::eTextChangeEvent)) { 184 AccTextChangeEvent* tc = downcast_accEvent(aEvent); 185 nsString text; 186 tc->GetModifiedText(text); 187 xpEvent = new xpcAccTextChangeEvent( 188 type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, 189 tc->GetStartOffset(), tc->GetLength(), tc->IsTextInserted(), text); 190 return xpEvent.forget(); 191 } 192 193 if (eventGroup & (1 << AccEvent::eHideEvent)) { 194 AccHideEvent* hideEvent = downcast_accEvent(aEvent); 195 xpEvent = new xpcAccHideEvent(type, ToXPC(acc), ToXPCDocument(doc), node, 196 fromUser, ToXPC(hideEvent->TargetParent()), 197 ToXPC(hideEvent->TargetNextSibling()), 198 ToXPC(hideEvent->TargetPrevSibling())); 199 return xpEvent.forget(); 200 } 201 202 if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) { 203 AccCaretMoveEvent* cm = downcast_accEvent(aEvent); 204 xpEvent = new xpcAccCaretMoveEvent( 205 type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, 206 cm->GetCaretOffset(), cm->IsSelectionCollapsed(), cm->IsAtEndOfLine(), 207 cm->GetGranularity()); 208 return xpEvent.forget(); 209 } 210 211 if (eventGroup & (1 << AccEvent::eTextSelChangeEvent)) { 212 AccTextSelChangeEvent* tsc = downcast_accEvent(aEvent); 213 AutoTArray<TextRange, 1> ranges; 214 tsc->SelectionRanges(&ranges); 215 216 nsCOMPtr<nsIMutableArray> xpcRanges = 217 do_CreateInstance(NS_ARRAY_CONTRACTID); 218 uint32_t len = ranges.Length(); 219 for (uint32_t idx = 0; idx < len; idx++) { 220 xpcRanges->AppendElement(new xpcAccessibleTextRange(ranges[idx])); 221 } 222 223 xpEvent = new xpcAccTextSelectionChangeEvent( 224 type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, xpcRanges); 225 return xpEvent.forget(); 226 } 227 228 if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) { 229 AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent); 230 nsString attribute; 231 oac->GetAttribute()->ToString(attribute); 232 xpEvent = new xpcAccObjectAttributeChangedEvent( 233 type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, attribute); 234 return xpEvent.forget(); 235 } 236 237 if (eventGroup & (1 << AccEvent::eScrollingEvent)) { 238 AccScrollingEvent* sa = downcast_accEvent(aEvent); 239 xpEvent = new xpcAccScrollingEvent( 240 type, ToXPC(acc), ToXPCDocument(doc), node, fromUser, sa->ScrollX(), 241 sa->ScrollY(), sa->MaxScrollX(), sa->MaxScrollY()); 242 return xpEvent.forget(); 243 } 244 245 if (eventGroup & (1 << AccEvent::eAnnouncementEvent)) { 246 AccAnnouncementEvent* aa = downcast_accEvent(aEvent); 247 xpEvent = new xpcAccAnnouncementEvent(type, ToXPC(acc), ToXPCDocument(doc), 248 node, fromUser, aa->Announcement(), 249 aa->Priority()); 250 return xpEvent.forget(); 251 } 252 253 xpEvent = 254 new xpcAccEvent(type, ToXPC(acc), ToXPCDocument(doc), node, fromUser); 255 return xpEvent.forget(); 256 }