accessible/src/generic/RootAccessible.cpp

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:a302b4daf6e5
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "RootAccessible.h"
7
8 #include "mozilla/ArrayUtils.h"
9
10 #define CreateEvent CreateEventA
11 #include "nsIDOMDocument.h"
12
13 #include "Accessible-inl.h"
14 #include "DocAccessible-inl.h"
15 #include "nsAccessibilityService.h"
16 #include "nsAccUtils.h"
17 #include "nsCoreUtils.h"
18 #include "nsEventShell.h"
19 #include "Relation.h"
20 #include "Role.h"
21 #include "States.h"
22 #ifdef MOZ_XUL
23 #include "XULTreeAccessible.h"
24 #endif
25
26 #include "mozilla/dom/Element.h"
27
28 #include "nsIAccessibleRelation.h"
29 #include "nsIDocShellTreeItem.h"
30 #include "nsIDocShellTreeOwner.h"
31 #include "mozilla/dom/Event.h"
32 #include "mozilla/dom/EventTarget.h"
33 #include "nsIDOMCustomEvent.h"
34 #include "nsIDOMXULMultSelectCntrlEl.h"
35 #include "nsIDocument.h"
36 #include "nsIInterfaceRequestorUtils.h"
37 #include "nsIPropertyBag2.h"
38 #include "nsIServiceManager.h"
39 #include "nsPIDOMWindow.h"
40 #include "nsIWebBrowserChrome.h"
41 #include "nsReadableUtils.h"
42 #include "nsFocusManager.h"
43
44 #ifdef MOZ_XUL
45 #include "nsIXULDocument.h"
46 #include "nsIXULWindow.h"
47 #endif
48
49 using namespace mozilla;
50 using namespace mozilla::a11y;
51 using namespace mozilla::dom;
52
53 ////////////////////////////////////////////////////////////////////////////////
54 // nsISupports
55
56 NS_IMPL_ISUPPORTS_INHERITED(RootAccessible, DocAccessible, nsIAccessibleDocument)
57
58 ////////////////////////////////////////////////////////////////////////////////
59 // Constructor/destructor
60
61 RootAccessible::
62 RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
63 nsIPresShell* aPresShell) :
64 DocAccessibleWrap(aDocument, aRootContent, aPresShell)
65 {
66 mType = eRootType;
67 }
68
69 RootAccessible::~RootAccessible()
70 {
71 }
72
73 ////////////////////////////////////////////////////////////////////////////////
74 // Accessible
75
76 ENameValueFlag
77 RootAccessible::Name(nsString& aName)
78 {
79 aName.Truncate();
80
81 if (mRoleMapEntry) {
82 Accessible::Name(aName);
83 if (!aName.IsEmpty())
84 return eNameOK;
85 }
86
87 mDocumentNode->GetTitle(aName);
88 return eNameOK;
89 }
90
91 role
92 RootAccessible::NativeRole()
93 {
94 // If it's a <dialog> or <wizard>, use roles::DIALOG instead
95 dom::Element* rootElm = mDocumentNode->GetRootElement();
96 if (rootElm && (rootElm->Tag() == nsGkAtoms::dialog ||
97 rootElm->Tag() == nsGkAtoms::wizard))
98 return roles::DIALOG;
99
100 return DocAccessibleWrap::NativeRole();
101 }
102
103 // RootAccessible protected member
104 #ifdef MOZ_XUL
105 uint32_t
106 RootAccessible::GetChromeFlags()
107 {
108 // Return the flag set for the top level window as defined
109 // by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
110 // Not simple: nsIXULWindow is not just a QI from nsIDOMWindow
111 nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mDocumentNode);
112 NS_ENSURE_TRUE(docShell, 0);
113 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
114 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
115 NS_ENSURE_TRUE(treeOwner, 0);
116 nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
117 if (!xulWin) {
118 return 0;
119 }
120 uint32_t chromeFlags;
121 xulWin->GetChromeFlags(&chromeFlags);
122 return chromeFlags;
123 }
124 #endif
125
126 uint64_t
127 RootAccessible::NativeState()
128 {
129 uint64_t state = DocAccessibleWrap::NativeState();
130 if (state & states::DEFUNCT)
131 return state;
132
133 #ifdef MOZ_XUL
134 uint32_t chromeFlags = GetChromeFlags();
135 if (chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE)
136 state |= states::SIZEABLE;
137 // If it has a titlebar it's movable
138 // XXX unless it's minimized or maximized, but not sure
139 // how to detect that
140 if (chromeFlags & nsIWebBrowserChrome::CHROME_TITLEBAR)
141 state |= states::MOVEABLE;
142 if (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL)
143 state |= states::MODAL;
144 #endif
145
146 nsFocusManager* fm = nsFocusManager::GetFocusManager();
147 if (fm && fm->GetActiveWindow() == mDocumentNode->GetWindow())
148 state |= states::ACTIVE;
149
150 return state;
151 }
152
153 const char* const kEventTypes[] = {
154 #ifdef DEBUG_DRAGDROPSTART
155 // Capture mouse over events and fire fake DRAGDROPSTART event to simplify
156 // debugging a11y objects with event viewers.
157 "mouseover",
158 #endif
159 // Fired when list or tree selection changes.
160 "select",
161 // Fired when value changes immediately, wether or not focused changed.
162 "ValueChange",
163 "AlertActive",
164 "TreeRowCountChanged",
165 "TreeInvalidated",
166 // add ourself as a OpenStateChange listener (custom event fired in tree.xml)
167 "OpenStateChange",
168 // add ourself as a CheckboxStateChange listener (custom event fired in HTMLInputElement.cpp)
169 "CheckboxStateChange",
170 // add ourself as a RadioStateChange Listener ( custom event fired in in HTMLInputElement.cpp & radio.xml)
171 "RadioStateChange",
172 "popupshown",
173 "popuphiding",
174 "DOMMenuInactive",
175 "DOMMenuItemActive",
176 "DOMMenuItemInactive",
177 "DOMMenuBarActive",
178 "DOMMenuBarInactive"
179 };
180
181 nsresult
182 RootAccessible::AddEventListeners()
183 {
184 // EventTarget interface allows to register event listeners to
185 // receive untrusted events (synthetic events generated by untrusted code).
186 // For example, XBL bindings implementations for elements that are hosted in
187 // non chrome document fire untrusted events.
188 nsCOMPtr<EventTarget> nstarget = mDocumentNode;
189
190 if (nstarget) {
191 for (const char* const* e = kEventTypes,
192 * const* e_end = ArrayEnd(kEventTypes);
193 e < e_end; ++e) {
194 nsresult rv = nstarget->AddEventListener(NS_ConvertASCIItoUTF16(*e),
195 this, true, true, 2);
196 NS_ENSURE_SUCCESS(rv, rv);
197 }
198 }
199
200 return DocAccessible::AddEventListeners();
201 }
202
203 nsresult
204 RootAccessible::RemoveEventListeners()
205 {
206 nsCOMPtr<EventTarget> target = mDocumentNode;
207 if (target) {
208 for (const char* const* e = kEventTypes,
209 * const* e_end = ArrayEnd(kEventTypes);
210 e < e_end; ++e) {
211 nsresult rv = target->RemoveEventListener(NS_ConvertASCIItoUTF16(*e), this, true);
212 NS_ENSURE_SUCCESS(rv, rv);
213 }
214 }
215
216 // Do this before removing clearing caret accessible, so that it can use
217 // shutdown the caret accessible's selection listener
218 DocAccessible::RemoveEventListeners();
219 return NS_OK;
220 }
221
222 ////////////////////////////////////////////////////////////////////////////////
223 // public
224
225 void
226 RootAccessible::DocumentActivated(DocAccessible* aDocument)
227 {
228 }
229
230 ////////////////////////////////////////////////////////////////////////////////
231 // nsIDOMEventListener
232
233 NS_IMETHODIMP
234 RootAccessible::HandleEvent(nsIDOMEvent* aDOMEvent)
235 {
236 MOZ_ASSERT(aDOMEvent);
237 Event* event = aDOMEvent->InternalDOMEvent();
238 nsCOMPtr<nsINode> origTargetNode = do_QueryInterface(event->GetOriginalTarget());
239 if (!origTargetNode)
240 return NS_OK;
241
242 #ifdef A11Y_LOG
243 if (logging::IsEnabled(logging::eDOMEvents)) {
244 nsAutoString eventType;
245 aDOMEvent->GetType(eventType);
246 logging::DOMEvent("handled", origTargetNode, eventType);
247 }
248 #endif
249
250 DocAccessible* document =
251 GetAccService()->GetDocAccessible(origTargetNode->OwnerDoc());
252
253 if (document) {
254 // Root accessible exists longer than any of its descendant documents so
255 // that we are guaranteed notification is processed before root accessible
256 // is destroyed.
257 document->HandleNotification<RootAccessible, nsIDOMEvent>
258 (this, &RootAccessible::ProcessDOMEvent, aDOMEvent);
259 }
260
261 return NS_OK;
262 }
263
264 // RootAccessible protected
265 void
266 RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
267 {
268 MOZ_ASSERT(aDOMEvent);
269 Event* event = aDOMEvent->InternalDOMEvent();
270 nsCOMPtr<nsINode> origTargetNode = do_QueryInterface(event->GetOriginalTarget());
271
272 nsAutoString eventType;
273 aDOMEvent->GetType(eventType);
274
275 #ifdef A11Y_LOG
276 if (logging::IsEnabled(logging::eDOMEvents))
277 logging::DOMEvent("processed", origTargetNode, eventType);
278 #endif
279
280 if (eventType.EqualsLiteral("popuphiding")) {
281 HandlePopupHidingEvent(origTargetNode);
282 return;
283 }
284
285 DocAccessible* targetDocument = GetAccService()->
286 GetDocAccessible(origTargetNode->OwnerDoc());
287 NS_ASSERTION(targetDocument, "No document while accessible is in document?!");
288
289 Accessible* accessible =
290 targetDocument->GetAccessibleOrContainer(origTargetNode);
291 if (!accessible)
292 return;
293
294 #ifdef MOZ_XUL
295 XULTreeAccessible* treeAcc = accessible->AsXULTree();
296 if (treeAcc) {
297 if (eventType.EqualsLiteral("TreeRowCountChanged")) {
298 HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
299 return;
300 }
301
302 if (eventType.EqualsLiteral("TreeInvalidated")) {
303 HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
304 return;
305 }
306 }
307 #endif
308
309 if (eventType.EqualsLiteral("RadioStateChange")) {
310 uint64_t state = accessible->State();
311 bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0;
312
313 if (accessible->NeedsDOMUIEvent()) {
314 nsRefPtr<AccEvent> accEvent =
315 new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
316 nsEventShell::FireEvent(accEvent);
317 }
318
319 if (isEnabled) {
320 FocusMgr()->ActiveItemChanged(accessible);
321 #ifdef A11Y_LOG
322 if (logging::IsEnabled(logging::eFocus))
323 logging::ActiveItemChangeCausedBy("RadioStateChange", accessible);
324 #endif
325 }
326
327 return;
328 }
329
330 if (eventType.EqualsLiteral("CheckboxStateChange")) {
331 if (accessible->NeedsDOMUIEvent()) {
332 uint64_t state = accessible->State();
333 bool isEnabled = !!(state & states::CHECKED);
334
335 nsRefPtr<AccEvent> accEvent =
336 new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
337 nsEventShell::FireEvent(accEvent);
338 }
339 return;
340 }
341
342 Accessible* treeItemAcc = nullptr;
343 #ifdef MOZ_XUL
344 // If it's a tree element, need the currently selected item.
345 if (treeAcc) {
346 treeItemAcc = accessible->CurrentItem();
347 if (treeItemAcc)
348 accessible = treeItemAcc;
349 }
350
351 if (treeItemAcc && eventType.EqualsLiteral("OpenStateChange")) {
352 uint64_t state = accessible->State();
353 bool isEnabled = (state & states::EXPANDED) != 0;
354
355 nsRefPtr<AccEvent> accEvent =
356 new AccStateChangeEvent(accessible, states::EXPANDED, isEnabled);
357 nsEventShell::FireEvent(accEvent);
358 return;
359 }
360
361 nsINode* targetNode = accessible->GetNode();
362 if (treeItemAcc && eventType.EqualsLiteral("select")) {
363 // XXX: We shouldn't be based on DOM select event which doesn't provide us
364 // any context info. We should integrate into nsTreeSelection instead.
365 // If multiselect tree, we should fire selectionadd or selection removed
366 if (FocusMgr()->HasDOMFocus(targetNode)) {
367 nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel =
368 do_QueryInterface(targetNode);
369 nsAutoString selType;
370 multiSel->GetSelType(selType);
371 if (selType.IsEmpty() || !selType.EqualsLiteral("single")) {
372 // XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
373 // for each tree item. Perhaps each tree item will need to cache its
374 // selection state and fire an event after a DOM "select" event when
375 // that state changes. XULTreeAccessible::UpdateTreeSelection();
376 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
377 accessible);
378 return;
379 }
380
381 nsRefPtr<AccSelChangeEvent> selChangeEvent =
382 new AccSelChangeEvent(treeAcc, treeItemAcc,
383 AccSelChangeEvent::eSelectionAdd);
384 nsEventShell::FireEvent(selChangeEvent);
385 return;
386 }
387 }
388 else
389 #endif
390 if (eventType.EqualsLiteral("AlertActive")) {
391 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible);
392 }
393 else if (eventType.EqualsLiteral("popupshown")) {
394 HandlePopupShownEvent(accessible);
395 }
396 else if (eventType.EqualsLiteral("DOMMenuInactive")) {
397 if (accessible->Role() == roles::MENUPOPUP) {
398 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
399 accessible);
400 }
401 }
402 else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
403 FocusMgr()->ActiveItemChanged(accessible);
404 #ifdef A11Y_LOG
405 if (logging::IsEnabled(logging::eFocus))
406 logging::ActiveItemChangeCausedBy("DOMMenuItemActive", accessible);
407 #endif
408 }
409 else if (eventType.EqualsLiteral("DOMMenuItemInactive")) {
410 // Process DOMMenuItemInactive event for autocomplete only because this is
411 // unique widget that may acquire focus from autocomplete popup while popup
412 // stays open and has no active item. In case of XUL tree autocomplete
413 // popup this event is fired for tree accessible.
414 Accessible* widget =
415 accessible->IsWidget() ? accessible : accessible->ContainerWidget();
416 if (widget && widget->IsAutoCompletePopup()) {
417 FocusMgr()->ActiveItemChanged(nullptr);
418 #ifdef A11Y_LOG
419 if (logging::IsEnabled(logging::eFocus))
420 logging::ActiveItemChangeCausedBy("DOMMenuItemInactive", accessible);
421 #endif
422 }
423 }
424 else if (eventType.EqualsLiteral("DOMMenuBarActive")) { // Always from user input
425 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START,
426 accessible, eFromUserInput);
427
428 // Notify of active item change when menubar gets active and if it has
429 // current item. This is a case of mouseover (set current menuitem) and
430 // mouse click (activate the menubar). If menubar doesn't have current item
431 // (can be a case of menubar activation from keyboard) then ignore this
432 // notification because later we'll receive DOMMenuItemActive event after
433 // current menuitem is set.
434 Accessible* activeItem = accessible->CurrentItem();
435 if (activeItem) {
436 FocusMgr()->ActiveItemChanged(activeItem);
437 #ifdef A11Y_LOG
438 if (logging::IsEnabled(logging::eFocus))
439 logging::ActiveItemChangeCausedBy("DOMMenuBarActive", accessible);
440 #endif
441 }
442 }
443 else if (eventType.EqualsLiteral("DOMMenuBarInactive")) { // Always from user input
444 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END,
445 accessible, eFromUserInput);
446
447 FocusMgr()->ActiveItemChanged(nullptr);
448 #ifdef A11Y_LOG
449 if (logging::IsEnabled(logging::eFocus))
450 logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible);
451 #endif
452 }
453 else if (accessible->NeedsDOMUIEvent() &&
454 eventType.EqualsLiteral("ValueChange")) {
455 targetDocument->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
456 accessible);
457 }
458 #ifdef DEBUG_DRAGDROPSTART
459 else if (eventType.EqualsLiteral("mouseover")) {
460 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
461 accessible);
462 }
463 #endif
464 }
465
466
467 ////////////////////////////////////////////////////////////////////////////////
468 // Accessible
469
470 void
471 RootAccessible::Shutdown()
472 {
473 // Called manually or by Accessible::LastRelease()
474 if (!PresShell())
475 return; // Already shutdown
476
477 DocAccessibleWrap::Shutdown();
478 }
479
480 // nsIAccessible method
481 Relation
482 RootAccessible::RelationByType(RelationType aType)
483 {
484 if (!mDocumentNode || aType != RelationType::EMBEDS)
485 return DocAccessibleWrap::RelationByType(aType);
486
487 nsIDOMWindow* rootWindow = mDocumentNode->GetWindow();
488 if (rootWindow) {
489 nsCOMPtr<nsIDOMWindow> contentWindow;
490 rootWindow->GetContent(getter_AddRefs(contentWindow));
491 if (contentWindow) {
492 nsCOMPtr<nsIDOMDocument> contentDOMDocument;
493 contentWindow->GetDocument(getter_AddRefs(contentDOMDocument));
494 nsCOMPtr<nsIDocument> contentDocumentNode =
495 do_QueryInterface(contentDOMDocument);
496 if (contentDocumentNode) {
497 DocAccessible* contentDocument =
498 GetAccService()->GetDocAccessible(contentDocumentNode);
499 if (contentDocument)
500 return Relation(contentDocument);
501 }
502 }
503 }
504
505 return Relation();
506 }
507
508 ////////////////////////////////////////////////////////////////////////////////
509 // Protected members
510
511 void
512 RootAccessible::HandlePopupShownEvent(Accessible* aAccessible)
513 {
514 roles::Role role = aAccessible->Role();
515
516 if (role == roles::MENUPOPUP) {
517 // Don't fire menupopup events for combobox and autocomplete lists.
518 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
519 aAccessible);
520 return;
521 }
522
523 if (role == roles::TOOLTIP) {
524 // There is a single <xul:tooltip> node which Mozilla moves around.
525 // The accessible for it stays the same no matter where it moves.
526 // AT's expect to get an EVENT_SHOW for the tooltip.
527 // In event callback the tooltip's accessible will be ready.
528 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SHOW, aAccessible);
529 return;
530 }
531
532 if (role == roles::COMBOBOX_LIST) {
533 // Fire expanded state change event for comboboxes and autocompeletes.
534 Accessible* combobox = aAccessible->Parent();
535 if (!combobox)
536 return;
537
538 roles::Role comboboxRole = combobox->Role();
539 if (comboboxRole == roles::COMBOBOX ||
540 comboboxRole == roles::AUTOCOMPLETE) {
541 nsRefPtr<AccEvent> event =
542 new AccStateChangeEvent(combobox, states::EXPANDED, true);
543 if (event)
544 nsEventShell::FireEvent(event);
545 }
546 }
547 }
548
549 void
550 RootAccessible::HandlePopupHidingEvent(nsINode* aPopupNode)
551 {
552 // Get popup accessible. There are cases when popup element isn't accessible
553 // but an underlying widget is and behaves like popup, an example is
554 // autocomplete popups.
555 DocAccessible* document = nsAccUtils::GetDocAccessibleFor(aPopupNode);
556 if (!document)
557 return;
558
559 Accessible* popup = document->GetAccessible(aPopupNode);
560 if (!popup) {
561 Accessible* popupContainer = document->GetContainerAccessible(aPopupNode);
562 if (!popupContainer)
563 return;
564
565 uint32_t childCount = popupContainer->ChildCount();
566 for (uint32_t idx = 0; idx < childCount; idx++) {
567 Accessible* child = popupContainer->GetChildAt(idx);
568 if (child->IsAutoCompletePopup()) {
569 popup = child;
570 break;
571 }
572 }
573
574 // No popup no events. Focus is managed by DOM. This is a case for
575 // menupopups of menus on Linux since there are no accessible for popups.
576 if (!popup)
577 return;
578 }
579
580 // In case of autocompletes and comboboxes fire state change event for
581 // expanded state. Note, HTML form autocomplete isn't a subject of state
582 // change event because they aren't autocompletes strictly speaking.
583 // When popup closes (except nested popups and menus) then fire focus event to
584 // where it was. The focus event is expected even if popup didn't take a focus.
585
586 static const uint32_t kNotifyOfFocus = 1;
587 static const uint32_t kNotifyOfState = 2;
588 uint32_t notifyOf = 0;
589
590 // HTML select is target of popuphidding event. Otherwise get container
591 // widget. No container widget means this is either tooltip or menupopup.
592 // No events in the former case.
593 Accessible* widget = nullptr;
594 if (popup->IsCombobox()) {
595 widget = popup;
596 } else {
597 widget = popup->ContainerWidget();
598 if (!widget) {
599 if (!popup->IsMenuPopup())
600 return;
601
602 widget = popup;
603 }
604 }
605
606 if (popup->IsAutoCompletePopup()) {
607 // No focus event for autocomplete because it's managed by
608 // DOMMenuItemInactive events.
609 if (widget->IsAutoComplete())
610 notifyOf = kNotifyOfState;
611
612 } else if (widget->IsCombobox()) {
613 // Fire focus for active combobox, otherwise the focus is managed by DOM
614 // focus notifications. Always fire state change event.
615 if (widget->IsActiveWidget())
616 notifyOf = kNotifyOfFocus;
617 notifyOf |= kNotifyOfState;
618
619 } else if (widget->IsMenuButton()) {
620 // Can be a part of autocomplete.
621 Accessible* compositeWidget = widget->ContainerWidget();
622 if (compositeWidget && compositeWidget->IsAutoComplete()) {
623 widget = compositeWidget;
624 notifyOf = kNotifyOfState;
625 }
626
627 // Autocomplete (like searchbar) can be inactive when popup hiddens
628 notifyOf |= kNotifyOfFocus;
629
630 } else if (widget == popup) {
631 // Top level context menus and alerts.
632 // Ignore submenus and menubar. When submenu is closed then sumbenu
633 // container menuitem takes a focus via DOMMenuItemActive notification.
634 // For menubars processing we listen DOMMenubarActive/Inactive
635 // notifications.
636 notifyOf = kNotifyOfFocus;
637 }
638
639 // Restore focus to where it was.
640 if (notifyOf & kNotifyOfFocus) {
641 FocusMgr()->ActiveItemChanged(nullptr);
642 #ifdef A11Y_LOG
643 if (logging::IsEnabled(logging::eFocus))
644 logging::ActiveItemChangeCausedBy("popuphiding", popup);
645 #endif
646 }
647
648 // Fire expanded state change event.
649 if (notifyOf & kNotifyOfState) {
650 nsRefPtr<AccEvent> event =
651 new AccStateChangeEvent(widget, states::EXPANDED, false);
652 document->FireDelayedEvent(event);
653 }
654 }
655
656 #ifdef MOZ_XUL
657 void
658 RootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent* aEvent,
659 XULTreeAccessible* aAccessible)
660 {
661 nsCOMPtr<nsIDOMCustomEvent> customEvent(do_QueryInterface(aEvent));
662 if (!customEvent)
663 return;
664
665 nsCOMPtr<nsIVariant> detailVariant;
666 customEvent->GetDetail(getter_AddRefs(detailVariant));
667 if (!detailVariant)
668 return;
669
670 nsCOMPtr<nsISupports> supports;
671 detailVariant->GetAsISupports(getter_AddRefs(supports));
672 nsCOMPtr<nsIPropertyBag2> propBag(do_QueryInterface(supports));
673 if (!propBag)
674 return;
675
676 nsresult rv;
677 int32_t index, count;
678 rv = propBag->GetPropertyAsInt32(NS_LITERAL_STRING("index"), &index);
679 if (NS_FAILED(rv))
680 return;
681
682 rv = propBag->GetPropertyAsInt32(NS_LITERAL_STRING("count"), &count);
683 if (NS_FAILED(rv))
684 return;
685
686 aAccessible->InvalidateCache(index, count);
687 }
688
689 void
690 RootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
691 XULTreeAccessible* aAccessible)
692 {
693 nsCOMPtr<nsIDOMCustomEvent> customEvent(do_QueryInterface(aEvent));
694 if (!customEvent)
695 return;
696
697 nsCOMPtr<nsIVariant> detailVariant;
698 customEvent->GetDetail(getter_AddRefs(detailVariant));
699 if (!detailVariant)
700 return;
701
702 nsCOMPtr<nsISupports> supports;
703 detailVariant->GetAsISupports(getter_AddRefs(supports));
704 nsCOMPtr<nsIPropertyBag2> propBag(do_QueryInterface(supports));
705 if (!propBag)
706 return;
707
708 int32_t startRow = 0, endRow = -1, startCol = 0, endCol = -1;
709 propBag->GetPropertyAsInt32(NS_LITERAL_STRING("startrow"),
710 &startRow);
711 propBag->GetPropertyAsInt32(NS_LITERAL_STRING("endrow"),
712 &endRow);
713 propBag->GetPropertyAsInt32(NS_LITERAL_STRING("startcolumn"),
714 &startCol);
715 propBag->GetPropertyAsInt32(NS_LITERAL_STRING("endcolumn"),
716 &endCol);
717
718 aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
719 }
720 #endif

mercurial