Line data Source code
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 0 : AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible,
33 0 : EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) :
34 0 : mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible)
35 : {
36 0 : if (aIsFromUserInput == eAutoDetect)
37 0 : mIsFromUserInput = EventStateManager::IsHandlingUserInput();
38 : 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 : }
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 : }
61 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
62 :
63 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef)
64 0 : 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 0 : AccTextChangeEvent::
79 : AccTextChangeEvent(Accessible* aAccessible, int32_t aStart,
80 : const nsAString& aModifiedText, bool aIsInserted,
81 0 : 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 0 : , mModifiedText(aModifiedText)
89 : {
90 : // XXX We should use IsFromUserInput here, but that isn't always correct
91 : // 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 0 : AccHideEvent::
101 0 : AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) :
102 : AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget),
103 0 : mNeedsShutdown(aNeedsShutdown)
104 : {
105 0 : mNextSibling = mAccessible->NextSibling();
106 0 : mPrevSibling = mAccessible->PrevSibling();
107 0 : }
108 :
109 :
110 : ////////////////////////////////////////////////////////////////////////////////
111 : // AccShowEvent
112 : ////////////////////////////////////////////////////////////////////////////////
113 :
114 0 : AccShowEvent::
115 0 : AccShowEvent(Accessible* aTarget) :
116 0 : AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget)
117 : {
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 0 : AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
129 : dom::Selection* aSelection,
130 0 : 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 0 : AccTextSelChangeEvent::IsCaretMoveOnly() const
139 : {
140 0 : return mSel->RangeCount() == 1 && mSel->IsCollapsed() &&
141 0 : ((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON |
142 0 : nsISelectionListener::COLLAPSETOEND_REASON)) == 0);
143 : }
144 :
145 : ////////////////////////////////////////////////////////////////////////////////
146 : // AccSelChangeEvent
147 : ////////////////////////////////////////////////////////////////////////////////
148 :
149 0 : AccSelChangeEvent::
150 : AccSelChangeEvent(Accessible* aWidget, Accessible* aItem,
151 0 : SelChangeType aSelChangeType) :
152 : AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange),
153 : mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType),
154 0 : mPreceedingCount(0), mPackedEvent(nullptr)
155 : {
156 0 : if (aSelChangeType == eSelectionAdd) {
157 0 : if (mWidget->GetSelectedItem(1))
158 0 : mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
159 : else
160 0 : mEventType = nsIAccessibleEvent::EVENT_SELECTION;
161 : } else {
162 0 : mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
163 : }
164 0 : }
165 :
166 :
167 : ////////////////////////////////////////////////////////////////////////////////
168 : // AccTableChangeEvent
169 : ////////////////////////////////////////////////////////////////////////////////
170 :
171 0 : AccTableChangeEvent::
172 : AccTableChangeEvent(Accessible* aAccessible, uint32_t aEventType,
173 0 : int32_t aRowOrColIndex, int32_t aNumRowsOrCols) :
174 : AccEvent(aEventType, aAccessible),
175 0 : mRowOrColIndex(aRowOrColIndex), mNumRowsOrCols(aNumRowsOrCols)
176 : {
177 0 : }
178 :
179 :
180 : ////////////////////////////////////////////////////////////////////////////////
181 : // AccVCChangeEvent
182 : ////////////////////////////////////////////////////////////////////////////////
183 :
184 0 : AccVCChangeEvent::
185 : AccVCChangeEvent(Accessible* aAccessible,
186 : Accessible* aOldAccessible,
187 : int32_t aOldStart, int32_t aOldEnd,
188 0 : int16_t aReason, EIsFromUserInput aIsFromUserInput) :
189 : AccEvent(::nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED, aAccessible,
190 : aIsFromUserInput),
191 : mOldAccessible(aOldAccessible), mOldStart(aOldStart), mOldEnd(aOldEnd),
192 0 : mReason(aReason)
193 : {
194 0 : }
195 :
196 : already_AddRefed<nsIAccessibleEvent>
197 0 : a11y::MakeXPCEvent(AccEvent* aEvent)
198 : {
199 0 : DocAccessible* doc = aEvent->Document();
200 0 : Accessible* acc = aEvent->GetAccessible();
201 0 : nsINode* node = acc->GetNode();
202 0 : nsIDOMNode* domNode = node ? node->AsDOMNode() : nullptr;
203 0 : bool fromUser = aEvent->IsFromUserInput();
204 0 : uint32_t type = aEvent->GetEventType();
205 0 : uint32_t eventGroup = aEvent->GetEventGroups();
206 0 : nsCOMPtr<nsIAccessibleEvent> xpEvent;
207 :
208 0 : if (eventGroup & (1 << AccEvent::eStateChangeEvent)) {
209 0 : AccStateChangeEvent* sc = downcast_accEvent(aEvent);
210 0 : bool extra = false;
211 0 : uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra);
212 0 : xpEvent = new xpcAccStateChangeEvent(type, ToXPC(acc), ToXPCDocument(doc),
213 : domNode, fromUser,
214 0 : state, extra, sc->IsStateEnabled());
215 0 : return xpEvent.forget();
216 : }
217 :
218 0 : if (eventGroup & (1 << AccEvent::eTextChangeEvent)) {
219 0 : AccTextChangeEvent* tc = downcast_accEvent(aEvent);
220 0 : nsString text;
221 0 : tc->GetModifiedText(text);
222 0 : xpEvent = new xpcAccTextChangeEvent(type, ToXPC(acc), ToXPCDocument(doc),
223 : domNode, fromUser,
224 0 : tc->GetStartOffset(), tc->GetLength(),
225 0 : tc->IsTextInserted(), text);
226 0 : return xpEvent.forget();
227 : }
228 :
229 0 : if (eventGroup & (1 << AccEvent::eHideEvent)) {
230 0 : AccHideEvent* hideEvent = downcast_accEvent(aEvent);
231 0 : xpEvent = new xpcAccHideEvent(type, ToXPC(acc), ToXPCDocument(doc),
232 : domNode, fromUser,
233 0 : ToXPC(hideEvent->TargetParent()),
234 0 : ToXPC(hideEvent->TargetNextSibling()),
235 0 : ToXPC(hideEvent->TargetPrevSibling()));
236 0 : return xpEvent.forget();
237 : }
238 :
239 0 : if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) {
240 0 : AccCaretMoveEvent* cm = downcast_accEvent(aEvent);
241 0 : xpEvent = new xpcAccCaretMoveEvent(type, ToXPC(acc), ToXPCDocument(doc),
242 : domNode, fromUser,
243 0 : cm->GetCaretOffset());
244 0 : return xpEvent.forget();
245 : }
246 :
247 0 : if (eventGroup & (1 << AccEvent::eVirtualCursorChangeEvent)) {
248 0 : AccVCChangeEvent* vcc = downcast_accEvent(aEvent);
249 : xpEvent = new xpcAccVirtualCursorChangeEvent(type,
250 0 : ToXPC(acc), ToXPCDocument(doc),
251 : domNode, fromUser,
252 0 : ToXPC(vcc->OldAccessible()),
253 0 : vcc->OldStartOffset(),
254 0 : vcc->OldEndOffset(),
255 0 : vcc->Reason());
256 0 : return xpEvent.forget();
257 : }
258 :
259 0 : if (eventGroup & (1 << AccEvent::eObjectAttrChangedEvent)) {
260 0 : AccObjectAttrChangedEvent* oac = downcast_accEvent(aEvent);
261 : xpEvent = new xpcAccObjectAttributeChangedEvent(type,
262 0 : ToXPC(acc),
263 0 : ToXPCDocument(doc), domNode,
264 : fromUser,
265 0 : oac->GetAttribute());
266 0 : return xpEvent.forget();
267 : }
268 :
269 0 : xpEvent = new xpcAccEvent(type, ToXPC(acc), ToXPCDocument(doc), domNode, fromUser);
270 0 : return xpEvent.forget();
271 : }
|