/src/mozilla-central/accessible/base/AccEvent.cpp
Line | Count | Source (jump to first uncovered line) |
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 "DocAccessible.h" |
11 | | #include "xpcAccEvents.h" |
12 | | #include "States.h" |
13 | | #include "xpcAccessibleDocument.h" |
14 | | |
15 | | #include "mozilla/EventStateManager.h" |
16 | | #include "mozilla/dom/Selection.h" |
17 | | |
18 | | using namespace mozilla; |
19 | | using namespace mozilla::a11y; |
20 | | |
21 | | static_assert(static_cast<bool>(eNoUserInput) == false && |
22 | | static_cast<bool>(eFromUserInput) == true, |
23 | | "EIsFromUserInput cannot be casted to bool"); |
24 | | |
25 | | //////////////////////////////////////////////////////////////////////////////// |
26 | | // AccEvent |
27 | | //////////////////////////////////////////////////////////////////////////////// |
28 | | |
29 | | //////////////////////////////////////////////////////////////////////////////// |
30 | | // AccEvent constructors |
31 | | |
32 | | AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible, |
33 | | EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) : |
34 | | mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible) |
35 | 0 | { |
36 | 0 | if (aIsFromUserInput == eAutoDetect) |
37 | 0 | mIsFromUserInput = EventStateManager::IsHandlingUserInput(); |
38 | 0 | else |
39 | 0 | mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false; |
40 | 0 | } |
41 | | |
42 | | //////////////////////////////////////////////////////////////////////////////// |
43 | | // AccEvent cycle collection |
44 | | |
45 | | NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent) |
46 | | |
47 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent) |
48 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible) |
49 | 0 | if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) { |
50 | 0 | tmEvent->SetNextEvent(nullptr); |
51 | 0 | tmEvent->SetPrevEvent(nullptr); |
52 | 0 | } |
53 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
54 | | |
55 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent) |
56 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible) |
57 | 0 | if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) { |
58 | 0 | CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext"); |
59 | 0 | CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent"); |
60 | 0 | } |
61 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
62 | | |
63 | | NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef) |
64 | | NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release) |
65 | | |
66 | | //////////////////////////////////////////////////////////////////////////////// |
67 | | //////////////////////////////////////////////////////////////////////////////// |
68 | | // AccTextChangeEvent |
69 | | //////////////////////////////////////////////////////////////////////////////// |
70 | | |
71 | | // Note: we pass in eAllowDupes to the base class because we don't support text |
72 | | // events coalescence. We fire delayed text change events in DocAccessible but |
73 | | // we continue to base the event off the accessible object rather than just the |
74 | | // node. This means we won't try to create an accessible based on the node when |
75 | | // we are ready to fire the event and so we will no longer assert at that point |
76 | | // if the node was removed from the document. Either way, the AT won't work with |
77 | | // a defunct accessible so the behaviour should be equivalent. |
78 | | AccTextChangeEvent:: |
79 | | AccTextChangeEvent(Accessible* aAccessible, int32_t aStart, |
80 | | const nsAString& aModifiedText, bool aIsInserted, |
81 | | EIsFromUserInput aIsFromUserInput) |
82 | | : AccEvent(aIsInserted ? |
83 | | static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_INSERTED) : |
84 | | static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_REMOVED), |
85 | | aAccessible, aIsFromUserInput, eAllowDupes) |
86 | | , mStart(aStart) |
87 | | , mIsInserted(aIsInserted) |
88 | | , mModifiedText(aModifiedText) |
89 | 0 | { |
90 | 0 | // XXX We should use IsFromUserInput here, but that isn't always correct |
91 | 0 | // when the text change isn't related to content insertion or removal. |
92 | 0 | mIsFromUserInput = mAccessible->State() & |
93 | 0 | (states::FOCUSED | states::EDITABLE); |
94 | 0 | } |
95 | | |
96 | | //////////////////////////////////////////////////////////////////////////////// |
97 | | // AccHideEvent |
98 | | //////////////////////////////////////////////////////////////////////////////// |
99 | | |
100 | | AccHideEvent:: |
101 | | AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) : |
102 | | AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget), |
103 | | mNeedsShutdown(aNeedsShutdown) |
104 | 0 | { |
105 | 0 | mNextSibling = mAccessible->NextSibling(); |
106 | 0 | mPrevSibling = mAccessible->PrevSibling(); |
107 | 0 | } |
108 | | |
109 | | |
110 | | //////////////////////////////////////////////////////////////////////////////// |
111 | | // AccShowEvent |
112 | | //////////////////////////////////////////////////////////////////////////////// |
113 | | |
114 | | AccShowEvent:: |
115 | | AccShowEvent(Accessible* aTarget) : |
116 | | AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget) |
117 | 0 | { |
118 | 0 | int32_t idx = aTarget->IndexInParent(); |
119 | 0 | MOZ_ASSERT(idx >= 0); |
120 | 0 | mInsertionIndex = idx; |
121 | 0 | } |
122 | | |
123 | | |
124 | | //////////////////////////////////////////////////////////////////////////////// |
125 | | // AccTextSelChangeEvent |
126 | | //////////////////////////////////////////////////////////////////////////////// |
127 | | |
128 | | AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget, |
129 | | dom::Selection* aSelection, |
130 | | int32_t aReason) : |
131 | | AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget, |
132 | | eAutoDetect, eCoalesceTextSelChange), |
133 | 0 | mSel(aSelection), mReason(aReason) {} |
134 | | |
135 | 0 | AccTextSelChangeEvent::~AccTextSelChangeEvent() { } |
136 | | |
137 | | bool |
138 | | AccTextSelChangeEvent::IsCaretMoveOnly() const |
139 | 0 | { |
140 | 0 | return mSel->RangeCount() == 1 && mSel->IsCollapsed() && |
141 | 0 | ((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON | |
142 | 0 | nsISelectionListener::COLLAPSETOEND_REASON)) == 0); |
143 | 0 | } |
144 | | |
145 | | //////////////////////////////////////////////////////////////////////////////// |
146 | | // AccSelChangeEvent |
147 | | //////////////////////////////////////////////////////////////////////////////// |
148 | | |
149 | | AccSelChangeEvent:: |
150 | | AccSelChangeEvent(Accessible* aWidget, Accessible* aItem, |
151 | | SelChangeType aSelChangeType) : |
152 | | AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange), |
153 | | mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType), |
154 | | mPreceedingCount(0), mPackedEvent(nullptr) |
155 | 0 | { |
156 | 0 | if (aSelChangeType == eSelectionAdd) { |
157 | 0 | if (mWidget->GetSelectedItem(1)) |
158 | 0 | mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; |
159 | 0 | else |
160 | 0 | mEventType = nsIAccessibleEvent::EVENT_SELECTION; |
161 | 0 | } else { |
162 | 0 | mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE; |
163 | 0 | } |
164 | 0 | } |
165 | | |
166 | | |
167 | | //////////////////////////////////////////////////////////////////////////////// |
168 | | // AccTableChangeEvent |
169 | | //////////////////////////////////////////////////////////////////////////////// |
170 | | |
171 | | AccTableChangeEvent:: |
172 | | AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType, |
173 | | int32_t aRowOrColIndex, int32_t aNumRowsOrCols) : |
174 | | AccEvent(aEventType, aAccessible), |
175 | | mRowOrColIndex(aRowOrColIndex), mNumRowsOrCols(aNumRowsOrCols) |
176 | 0 | { |
177 | 0 | } |
178 | | |
179 | | |
180 | | //////////////////////////////////////////////////////////////////////////////// |
181 | | // AccVCChangeEvent |
182 | | //////////////////////////////////////////////////////////////////////////////// |
183 | | |
184 | | AccVCChangeEvent:: |
185 | | AccVCChangeEvent(Accessible* aAccessible, |
186 | | Accessible* aOldAccessible, |
187 | | int32_t aOldStart, int32_t aOldEnd, |
188 | | Accessible* aNewAccessible, |
189 | | int32_t aNewStart, int32_t aNewEnd, |
190 | | int16_t aReason, int16_t aBoundaryType, |
191 | | EIsFromUserInput aIsFromUserInput) : |
192 | | AccEvent(::nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED, aAccessible, |
193 | | aIsFromUserInput), |
194 | | mOldAccessible(aOldAccessible), mNewAccessible(aNewAccessible), |
195 | | mOldStart(aOldStart), mNewStart(aNewStart), |
196 | | mOldEnd(aOldEnd), mNewEnd(aNewEnd), |
197 | | mReason(aReason), mBoundaryType(aBoundaryType) |
198 | 0 | { |
199 | 0 | } |
200 | | |
201 | | already_AddRefed<nsIAccessibleEvent> |
202 | | a11y::MakeXPCEvent(AccEvent* aEvent) |
203 | 0 | { |
204 | 0 | DocAccessible* doc = aEvent->Document(); |
205 | 0 | Accessible* acc = aEvent->GetAccessible(); |
206 | 0 | nsINode* node = acc->GetNode(); |
207 | 0 | bool fromUser = aEvent->IsFromUserInput(); |
208 | 0 | uint32_t type = aEvent->GetEventType(); |
209 | 0 | uint32_t eventGroup = aEvent->GetEventGroups(); |
210 | 0 | nsCOMPtr<nsIAccessibleEvent> xpEvent; |
211 | 0 |
|
212 | 0 | if (eventGroup & (1 << AccEvent::eStateChangeEvent)) { |
213 | 0 | AccStateChangeEvent* sc = downcast_accEvent(aEvent); |
214 | 0 | bool extra = false; |
215 | 0 | uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra); |
216 | 0 | xpEvent = new xpcAccStateChangeEvent(type, ToXPC(acc), ToXPCDocument(doc), |
217 | 0 | node, fromUser, |
218 | 0 | state, extra, sc->IsStateEnabled()); |
219 | 0 | return xpEvent.forget(); |
220 | 0 | } |
221 | 0 | |
222 | 0 | if (eventGroup & (1 << AccEvent::eTextChangeEvent)) { |
223 | 0 | AccTextChangeEvent* tc = downcast_accEvent(aEvent); |
224 | 0 | nsString text; |
225 | 0 | tc->GetModifiedText(text); |
226 | 0 | xpEvent = new xpcAccTextChangeEvent(type, ToXPC(acc), ToXPCDocument(doc), |
227 | 0 | node, fromUser, |
228 | 0 | tc->GetStartOffset(), tc->GetLength(), |
229 | 0 | tc->IsTextInserted(), text); |
230 | 0 | return xpEvent.forget(); |
231 | 0 | } |
232 | 0 | |
233 | 0 | if (eventGroup & (1 << AccEvent::eHideEvent)) { |
234 | 0 | AccHideEvent* hideEvent = downcast_accEvent(aEvent); |
235 | 0 | xpEvent = new xpcAccHideEvent(type, ToXPC(acc), ToXPCDocument(doc), |
236 | 0 | node, fromUser, |
237 | 0 | ToXPC(hideEvent->TargetParent()), |
238 | 0 | ToXPC(hideEvent->TargetNextSibling()), |
239 | 0 | ToXPC(hideEvent->TargetPrevSibling())); |
240 | 0 | return xpEvent.forget(); |
241 | 0 | } |
242 | 0 | |
243 | 0 | if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) { |
244 | 0 | AccCaretMoveEvent* cm = downcast_accEvent(aEvent); |
245 | 0 | xpEvent = new xpcAccCaretMoveEvent(type, ToXPC(acc), ToXPCDocument(doc), |
246 | 0 | node, fromUser, |
247 | 0 | cm->GetCaretOffset()); |
248 | 0 | return xpEvent.forget(); |
249 | 0 | } |
250 | 0 | |
251 | 0 | if (eventGroup & (1 << AccEvent::eVirtualCursorChangeEvent)) { |
252 | 0 | AccVCChangeEvent* vcc = downcast_accEvent(aEvent); |
253 | 0 | xpEvent = new xpcAccVirtualCursorChangeEvent(type, |
254 | 0 | ToXPC(acc), ToXPCDocument(doc), |
255 | 0 | node, fromUser, |
256 | 0 | ToXPC(vcc->OldAccessible()), |
257 | 0 | vcc->OldStartOffset(), |
258 | 0 | vcc->OldEndOffset(), |
259 | 0 | ToXPC(vcc->NewAccessible()), |
260 | 0 | vcc->NewStartOffset(), |
261 | 0 | vcc->NewEndOffset(), |
262 | 0 | vcc->Reason(), |
263 | 0 | vcc->BoundaryType()); |
264 | 0 | return xpEvent.forget(); |
265 | 0 | } |
266 | 0 | |
267 | 0 | if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) { |
268 | 0 | AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent); |
269 | 0 | nsString attribute; |
270 | 0 | oac->GetAttribute()->ToString(attribute); |
271 | 0 | xpEvent = new xpcAccObjectAttributeChangedEvent(type, |
272 | 0 | ToXPC(acc), |
273 | 0 | ToXPCDocument(doc), node, |
274 | 0 | fromUser, |
275 | 0 | attribute); |
276 | 0 | return xpEvent.forget(); |
277 | 0 | } |
278 | 0 | |
279 | 0 | if (eventGroup & (1 << AccEvent::eScrollingEvent)) { |
280 | 0 | AccScrollingEvent* sa = downcast_accEvent(aEvent); |
281 | 0 | xpEvent = new xpcAccScrollingEvent(type, ToXPC(acc), ToXPCDocument(doc), node, |
282 | 0 | fromUser, sa->ScrollX(), sa->ScrollY(), |
283 | 0 | sa->MaxScrollX(), sa->MaxScrollY()); |
284 | 0 | } |
285 | 0 |
|
286 | 0 | xpEvent = new xpcAccEvent(type, ToXPC(acc), ToXPCDocument(doc), node, fromUser); |
287 | 0 | return xpEvent.forget(); |
288 | 0 | } |