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