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/. */
9 #include "nsAccUtils.h"
10 #include "xpcAccEvents.h"
12 #include "TextRange.h"
13 #include "xpcAccessibleDocument.h"
14 #include "xpcAccessibleTextRange.h"
16 #include "mozilla/dom/Selection.h"
17 #include "mozilla/dom/UserActivation.h"
19 #include "nsComponentManagerUtils.h"
20 #include "nsIMutableArray.h"
22 using namespace mozilla
;
23 using namespace mozilla::a11y
;
25 static_assert(static_cast<bool>(eNoUserInput
) == false &&
26 static_cast<bool>(eFromUserInput
) == true,
27 "EIsFromUserInput cannot be casted to bool");
29 ////////////////////////////////////////////////////////////////////////////////
31 ////////////////////////////////////////////////////////////////////////////////
33 ////////////////////////////////////////////////////////////////////////////////
34 // AccEvent constructors
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();
42 mIsFromUserInput
= aIsFromUserInput
== eFromUserInput
? true : false;
46 ////////////////////////////////////////////////////////////////////////////////
47 // AccEvent cycle collection
49 NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent
)
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);
57 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
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");
65 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
67 ////////////////////////////////////////////////////////////////////////////////
68 ////////////////////////////////////////////////////////////////////////////////
70 ////////////////////////////////////////////////////////////////////////////////
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
,
81 const nsAString
& aModifiedText
,
83 EIsFromUserInput aIsFromUserInput
)
86 ? static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_INSERTED
)
87 : static_cast<uint32_t>(nsIAccessibleEvent::EVENT_TEXT_REMOVED
),
88 aAccessible
, aIsFromUserInput
, eAllowDupes
),
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.
95 mAccessible
->State() & (states::FOCUSED
| states::EDITABLE
);
98 ////////////////////////////////////////////////////////////////////////////////
100 ////////////////////////////////////////////////////////////////////////////////
102 AccHideEvent::AccHideEvent(LocalAccessible
* aTarget
, bool aNeedsShutdown
)
103 : AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE
, aTarget
),
104 mNeedsShutdown(aNeedsShutdown
) {
105 mNextSibling
= mAccessible
->LocalNextSibling();
106 mPrevSibling
= mAccessible
->LocalPrevSibling();
109 ////////////////////////////////////////////////////////////////////////////////
111 ////////////////////////////////////////////////////////////////////////////////
113 ////////////////////////////////////////////////////////////////////////////////
114 // AccTextSelChangeEvent
115 ////////////////////////////////////////////////////////////////////////////////
117 AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible
* aTarget
,
118 dom::Selection
* aSelection
,
120 int32_t aGranularity
)
121 : AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED
, aTarget
,
122 eAutoDetect
, eCoalesceTextSelChange
),
125 mGranularity(aGranularity
) {}
127 AccTextSelChangeEvent::~AccTextSelChangeEvent() {}
129 bool AccTextSelChangeEvent::IsCaretMoveOnly() const {
130 return mSel
->RangeCount() == 1 && mSel
->IsCollapsed() &&
131 ((mReason
& (nsISelectionListener::COLLAPSETOSTART_REASON
|
132 nsISelectionListener::COLLAPSETOEND_REASON
)) == 0);
135 void AccTextSelChangeEvent::SelectionRanges(
136 nsTArray
<TextRange
>* aRanges
) const {
137 TextRange::TextRangesFromSelection(mSel
, aRanges
);
140 ////////////////////////////////////////////////////////////////////////////////
142 ////////////////////////////////////////////////////////////////////////////////
144 AccSelChangeEvent::AccSelChangeEvent(LocalAccessible
* aWidget
,
145 LocalAccessible
* aItem
,
146 SelChangeType aSelChangeType
)
147 : AccEvent(0, aItem
, eAutoDetect
, eCoalesceSelectionChange
),
150 mSelChangeType(aSelChangeType
),
152 mPackedEvent(nullptr) {
153 if (aSelChangeType
== eSelectionAdd
) {
154 if (mWidget
->GetSelectedItem(1)) {
155 mEventType
= nsIAccessibleEvent::EVENT_SELECTION_ADD
;
157 mEventType
= nsIAccessibleEvent::EVENT_SELECTION
;
160 mEventType
= nsIAccessibleEvent::EVENT_SELECTION_REMOVE
;
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
;
173 if (eventGroup
& (1 << AccEvent::eStateChangeEvent
)) {
174 AccStateChangeEvent
* sc
= downcast_accEvent(aEvent
);
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();
183 if (eventGroup
& (1 << AccEvent::eTextChangeEvent
)) {
184 AccTextChangeEvent
* tc
= downcast_accEvent(aEvent
);
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();
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();
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();
211 if (eventGroup
& (1 << AccEvent::eTextSelChangeEvent
)) {
212 AccTextSelChangeEvent
* tsc
= downcast_accEvent(aEvent
);
213 AutoTArray
<TextRange
, 1> ranges
;
214 tsc
->SelectionRanges(&ranges
);
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
]));
223 xpEvent
= new xpcAccTextSelectionChangeEvent(
224 type
, ToXPC(acc
), ToXPCDocument(doc
), node
, fromUser
, xpcRanges
);
225 return xpEvent
.forget();
228 if (eventGroup
& (1 << AccEvent::eObjectAttrChangedEvent
)) {
229 AccObjectAttrChangedEvent
* oac
= downcast_accEvent(aEvent
);
231 oac
->GetAttribute()->ToString(attribute
);
232 xpEvent
= new xpcAccObjectAttributeChangedEvent(
233 type
, ToXPC(acc
), ToXPCDocument(doc
), node
, fromUser
, attribute
);
234 return xpEvent
.forget();
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();
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(),
250 return xpEvent
.forget();
254 new xpcAccEvent(type
, ToXPC(acc
), ToXPCDocument(doc
), node
, fromUser
);
255 return xpEvent
.forget();