1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2003
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Aaron Leventhal <aaronl@netscape.com> <original author>
24 : * Alexander Surkov <surkov.alexander@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "AccEvent.h"
41 :
42 : #include "nsAccessibilityService.h"
43 : #include "nsAccUtils.h"
44 : #include "nsApplicationAccessibleWrap.h"
45 : #include "nsDocAccessible.h"
46 : #include "nsIAccessibleText.h"
47 : #ifdef MOZ_XUL
48 : #include "nsXULTreeAccessible.h"
49 : #endif
50 : #include "nsAccEvent.h"
51 :
52 : #include "nsIDOMDocument.h"
53 : #include "nsEventStateManager.h"
54 : #include "nsIServiceManager.h"
55 : #ifdef MOZ_XUL
56 : #include "nsIDOMXULMultSelectCntrlEl.h"
57 : #endif
58 :
59 : ////////////////////////////////////////////////////////////////////////////////
60 : // AccEvent
61 : ////////////////////////////////////////////////////////////////////////////////
62 :
63 : ////////////////////////////////////////////////////////////////////////////////
64 : // AccEvent constructors
65 :
66 0 : AccEvent::AccEvent(PRUint32 aEventType, nsAccessible* aAccessible,
67 : EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) :
68 0 : mEventType(aEventType), mEventRule(aEventRule), mAccessible(aAccessible)
69 : {
70 0 : CaptureIsFromUserInput(aIsFromUserInput);
71 0 : }
72 :
73 0 : AccEvent::AccEvent(PRUint32 aEventType, nsINode* aNode,
74 : EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) :
75 0 : mEventType(aEventType), mEventRule(aEventRule), mNode(aNode)
76 : {
77 0 : CaptureIsFromUserInput(aIsFromUserInput);
78 0 : }
79 :
80 : ////////////////////////////////////////////////////////////////////////////////
81 : // AccEvent public methods
82 :
83 : nsAccessible *
84 0 : AccEvent::GetAccessible()
85 : {
86 0 : if (!mAccessible)
87 0 : mAccessible = GetAccessibleForNode();
88 :
89 0 : return mAccessible;
90 : }
91 :
92 : nsINode*
93 0 : AccEvent::GetNode()
94 : {
95 0 : if (!mNode && mAccessible)
96 0 : mNode = mAccessible->GetNode();
97 :
98 0 : return mNode;
99 : }
100 :
101 : nsDocAccessible*
102 0 : AccEvent::GetDocAccessible()
103 : {
104 0 : nsINode *node = GetNode();
105 0 : if (node)
106 0 : return GetAccService()->GetDocAccessible(node->OwnerDoc());
107 :
108 0 : return nsnull;
109 : }
110 :
111 : already_AddRefed<nsAccEvent>
112 0 : AccEvent::CreateXPCOMObject()
113 : {
114 0 : nsAccEvent* event = new nsAccEvent(this);
115 0 : NS_IF_ADDREF(event);
116 0 : return event;
117 : }
118 :
119 : ////////////////////////////////////////////////////////////////////////////////
120 : // AccEvent cycle collection
121 :
122 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent)
123 :
124 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(AccEvent)
125 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAccessible)
126 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
127 :
128 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(AccEvent)
129 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAccessible");
130 0 : cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mAccessible));
131 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
132 :
133 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef)
134 0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release)
135 :
136 : ////////////////////////////////////////////////////////////////////////////////
137 : // AccEvent protected methods
138 :
139 : nsAccessible*
140 0 : AccEvent::GetAccessibleForNode() const
141 : {
142 0 : return mNode ? GetAccService()->GetAccessible(mNode, nsnull) : nsnull;
143 : }
144 :
145 : void
146 0 : AccEvent::CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput)
147 : {
148 0 : nsINode *targetNode = GetNode();
149 :
150 : #ifdef DEBUG
151 0 : if (!targetNode) {
152 : // XXX: remove this hack during reorganization of 506907. Meanwhile we
153 : // want to get rid an assertion for application accessible events which
154 : // don't have DOM node (see bug 506206).
155 : nsApplicationAccessible *applicationAcc =
156 0 : nsAccessNode::GetApplicationAccessible();
157 :
158 0 : if (mAccessible != static_cast<nsIAccessible*>(applicationAcc))
159 0 : NS_ASSERTION(targetNode, "There should always be a DOM node for an event");
160 : }
161 : #endif
162 :
163 0 : if (aIsFromUserInput != eAutoDetect) {
164 0 : mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false;
165 0 : return;
166 : }
167 :
168 0 : if (!targetNode)
169 0 : return;
170 :
171 0 : nsIPresShell *presShell = nsCoreUtils::GetPresShellFor(targetNode);
172 0 : if (!presShell) {
173 0 : NS_NOTREACHED("Threre should always be an pres shell for an event");
174 0 : return;
175 : }
176 :
177 0 : nsEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
178 0 : if (!esm) {
179 0 : NS_NOTREACHED("There should always be an ESM for an event");
180 0 : return;
181 : }
182 :
183 0 : mIsFromUserInput = esm->IsHandlingUserInputExternal();
184 : }
185 :
186 :
187 : ////////////////////////////////////////////////////////////////////////////////
188 : // AccStateChangeEvent
189 : ////////////////////////////////////////////////////////////////////////////////
190 :
191 : // Note: we pass in eAllowDupes to the base class because we don't currently
192 : // support correct state change coalescence (XXX Bug 569356). Also we need to
193 : // decide how to coalesce events created via accessible (instead of node).
194 0 : AccStateChangeEvent::
195 : AccStateChangeEvent(nsAccessible* aAccessible, PRUint64 aState,
196 : bool aIsEnabled, EIsFromUserInput aIsFromUserInput):
197 : AccEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible,
198 : aIsFromUserInput, eAllowDupes),
199 0 : mState(aState), mIsEnabled(aIsEnabled)
200 : {
201 0 : }
202 :
203 0 : AccStateChangeEvent::
204 : AccStateChangeEvent(nsINode* aNode, PRUint64 aState, bool aIsEnabled):
205 : AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode,
206 : eAutoDetect, eAllowDupes),
207 0 : mState(aState), mIsEnabled(aIsEnabled)
208 : {
209 0 : }
210 :
211 0 : AccStateChangeEvent::
212 : AccStateChangeEvent(nsINode* aNode, PRUint64 aState) :
213 : AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode,
214 : eAutoDetect, eAllowDupes),
215 0 : mState(aState)
216 : {
217 : // Use GetAccessibleForNode() because we do not want to store an accessible
218 : // since it leads to problems with delayed events in the case when
219 : // an accessible gets reorder event before delayed event is processed.
220 0 : nsAccessible *accessible = GetAccessibleForNode();
221 0 : mIsEnabled = accessible && ((accessible->State() & mState) != 0);
222 0 : }
223 :
224 : already_AddRefed<nsAccEvent>
225 0 : AccStateChangeEvent::CreateXPCOMObject()
226 : {
227 0 : nsAccEvent* event = new nsAccStateChangeEvent(this);
228 0 : NS_IF_ADDREF(event);
229 0 : return event;
230 : }
231 :
232 :
233 : ////////////////////////////////////////////////////////////////////////////////
234 : // AccTextChangeEvent
235 : ////////////////////////////////////////////////////////////////////////////////
236 :
237 : // Note: we pass in eAllowDupes to the base class because we don't support text
238 : // events coalescence. We fire delayed text change events in nsDocAccessible but
239 : // we continue to base the event off the accessible object rather than just the
240 : // node. This means we won't try to create an accessible based on the node when
241 : // we are ready to fire the event and so we will no longer assert at that point
242 : // if the node was removed from the document. Either way, the AT won't work with
243 : // a defunct accessible so the behaviour should be equivalent.
244 : // XXX revisit this when coalescence is faster (eCoalesceFromSameSubtree)
245 0 : AccTextChangeEvent::
246 : AccTextChangeEvent(nsAccessible* aAccessible, PRInt32 aStart,
247 : const nsAString& aModifiedText, bool aIsInserted,
248 : EIsFromUserInput aIsFromUserInput)
249 : : AccEvent(aIsInserted ?
250 : static_cast<PRUint32>(nsIAccessibleEvent::EVENT_TEXT_INSERTED) :
251 : static_cast<PRUint32>(nsIAccessibleEvent::EVENT_TEXT_REMOVED),
252 : aAccessible, aIsFromUserInput, eAllowDupes)
253 : , mStart(aStart)
254 : , mIsInserted(aIsInserted)
255 0 : , mModifiedText(aModifiedText)
256 : {
257 0 : }
258 :
259 : already_AddRefed<nsAccEvent>
260 0 : AccTextChangeEvent::CreateXPCOMObject()
261 : {
262 0 : nsAccEvent* event = new nsAccTextChangeEvent(this);
263 0 : NS_IF_ADDREF(event);
264 0 : return event;
265 : }
266 :
267 :
268 : ////////////////////////////////////////////////////////////////////////////////
269 : // AccMutationEvent
270 : ////////////////////////////////////////////////////////////////////////////////
271 :
272 0 : AccMutationEvent::
273 : AccMutationEvent(PRUint32 aEventType, nsAccessible* aTarget,
274 : nsINode* aTargetNode) :
275 0 : AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceFromSameSubtree)
276 : {
277 0 : mNode = aTargetNode;
278 0 : }
279 :
280 :
281 : ////////////////////////////////////////////////////////////////////////////////
282 : // AccHideEvent
283 : ////////////////////////////////////////////////////////////////////////////////
284 :
285 0 : AccHideEvent::
286 : AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode) :
287 0 : AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode)
288 : {
289 0 : mParent = mAccessible->Parent();
290 0 : mNextSibling = mAccessible->NextSibling();
291 0 : mPrevSibling = mAccessible->PrevSibling();
292 0 : }
293 :
294 : already_AddRefed<nsAccEvent>
295 0 : AccHideEvent::CreateXPCOMObject()
296 : {
297 0 : nsAccEvent* event = new nsAccHideEvent(this);
298 0 : NS_ADDREF(event);
299 0 : return event;
300 : }
301 :
302 :
303 : ////////////////////////////////////////////////////////////////////////////////
304 : // AccShowEvent
305 : ////////////////////////////////////////////////////////////////////////////////
306 :
307 0 : AccShowEvent::
308 : AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode) :
309 0 : AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode)
310 : {
311 0 : }
312 :
313 :
314 : ////////////////////////////////////////////////////////////////////////////////
315 : // AccCaretMoveEvent
316 : ////////////////////////////////////////////////////////////////////////////////
317 :
318 0 : AccCaretMoveEvent::
319 : AccCaretMoveEvent(nsAccessible* aAccessible, PRInt32 aCaretOffset) :
320 : AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible),
321 0 : mCaretOffset(aCaretOffset)
322 : {
323 0 : }
324 :
325 0 : AccCaretMoveEvent::
326 : AccCaretMoveEvent(nsINode* aNode) :
327 : AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode),
328 0 : mCaretOffset(-1)
329 : {
330 0 : }
331 :
332 : already_AddRefed<nsAccEvent>
333 0 : AccCaretMoveEvent::CreateXPCOMObject()
334 : {
335 0 : nsAccEvent* event = new nsAccCaretMoveEvent(this);
336 0 : NS_IF_ADDREF(event);
337 0 : return event;
338 : }
339 :
340 :
341 : ////////////////////////////////////////////////////////////////////////////////
342 : // AccSelChangeEvent
343 : ////////////////////////////////////////////////////////////////////////////////
344 :
345 0 : AccSelChangeEvent::
346 : AccSelChangeEvent(nsAccessible* aWidget, nsAccessible* aItem,
347 : SelChangeType aSelChangeType) :
348 : AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange),
349 : mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType),
350 0 : mPreceedingCount(0), mPackedEvent(nsnull)
351 : {
352 0 : if (aSelChangeType == eSelectionAdd) {
353 0 : if (mWidget->GetSelectedItem(1))
354 0 : mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD;
355 : else
356 0 : mEventType = nsIAccessibleEvent::EVENT_SELECTION;
357 : } else {
358 0 : mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE;
359 : }
360 0 : }
361 :
362 :
363 : ////////////////////////////////////////////////////////////////////////////////
364 : // AccTableChangeEvent
365 : ////////////////////////////////////////////////////////////////////////////////
366 :
367 0 : AccTableChangeEvent::
368 : AccTableChangeEvent(nsAccessible* aAccessible, PRUint32 aEventType,
369 : PRInt32 aRowOrColIndex, PRInt32 aNumRowsOrCols) :
370 : AccEvent(aEventType, aAccessible),
371 0 : mRowOrColIndex(aRowOrColIndex), mNumRowsOrCols(aNumRowsOrCols)
372 : {
373 0 : }
374 :
375 : already_AddRefed<nsAccEvent>
376 0 : AccTableChangeEvent::CreateXPCOMObject()
377 : {
378 0 : nsAccEvent* event = new nsAccTableChangeEvent(this);
379 0 : NS_IF_ADDREF(event);
380 0 : return event;
381 : }
382 :
383 :
384 : ////////////////////////////////////////////////////////////////////////////////
385 : // AccVCChangeEvent
386 : ////////////////////////////////////////////////////////////////////////////////
387 :
388 0 : AccVCChangeEvent::
389 : AccVCChangeEvent(nsAccessible* aAccessible,
390 : nsIAccessible* aOldAccessible,
391 : PRInt32 aOldStart, PRInt32 aOldEnd) :
392 : AccEvent(::nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED, aAccessible),
393 0 : mOldAccessible(aOldAccessible), mOldStart(aOldStart), mOldEnd(aOldEnd)
394 : {
395 0 : }
396 :
397 : already_AddRefed<nsAccEvent>
398 0 : AccVCChangeEvent::CreateXPCOMObject()
399 : {
400 0 : nsAccEvent* event = new nsAccVirtualCursorChangeEvent(this);
401 0 : NS_ADDREF(event);
402 0 : return event;
403 4392 : }
|