Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
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/. */
6 #include "RootAccessible.h"
8 #include "mozilla/ArrayUtils.h"
10 #define CreateEvent CreateEventA
11 #include "nsIDOMDocument.h"
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
26 #include "mozilla/dom/Element.h"
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"
44 #ifdef MOZ_XUL
45 #include "nsIXULDocument.h"
46 #include "nsIXULWindow.h"
47 #endif
49 using namespace mozilla;
50 using namespace mozilla::a11y;
51 using namespace mozilla::dom;
53 ////////////////////////////////////////////////////////////////////////////////
54 // nsISupports
56 NS_IMPL_ISUPPORTS_INHERITED(RootAccessible, DocAccessible, nsIAccessibleDocument)
58 ////////////////////////////////////////////////////////////////////////////////
59 // Constructor/destructor
61 RootAccessible::
62 RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
63 nsIPresShell* aPresShell) :
64 DocAccessibleWrap(aDocument, aRootContent, aPresShell)
65 {
66 mType = eRootType;
67 }
69 RootAccessible::~RootAccessible()
70 {
71 }
73 ////////////////////////////////////////////////////////////////////////////////
74 // Accessible
76 ENameValueFlag
77 RootAccessible::Name(nsString& aName)
78 {
79 aName.Truncate();
81 if (mRoleMapEntry) {
82 Accessible::Name(aName);
83 if (!aName.IsEmpty())
84 return eNameOK;
85 }
87 mDocumentNode->GetTitle(aName);
88 return eNameOK;
89 }
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;
100 return DocAccessibleWrap::NativeRole();
101 }
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
126 uint64_t
127 RootAccessible::NativeState()
128 {
129 uint64_t state = DocAccessibleWrap::NativeState();
130 if (state & states::DEFUNCT)
131 return state;
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
146 nsFocusManager* fm = nsFocusManager::GetFocusManager();
147 if (fm && fm->GetActiveWindow() == mDocumentNode->GetWindow())
148 state |= states::ACTIVE;
150 return state;
151 }
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 };
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;
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 }
200 return DocAccessible::AddEventListeners();
201 }
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 }
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 }
222 ////////////////////////////////////////////////////////////////////////////////
223 // public
225 void
226 RootAccessible::DocumentActivated(DocAccessible* aDocument)
227 {
228 }
230 ////////////////////////////////////////////////////////////////////////////////
231 // nsIDOMEventListener
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;
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
250 DocAccessible* document =
251 GetAccService()->GetDocAccessible(origTargetNode->OwnerDoc());
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 }
261 return NS_OK;
262 }
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());
272 nsAutoString eventType;
273 aDOMEvent->GetType(eventType);
275 #ifdef A11Y_LOG
276 if (logging::IsEnabled(logging::eDOMEvents))
277 logging::DOMEvent("processed", origTargetNode, eventType);
278 #endif
280 if (eventType.EqualsLiteral("popuphiding")) {
281 HandlePopupHidingEvent(origTargetNode);
282 return;
283 }
285 DocAccessible* targetDocument = GetAccService()->
286 GetDocAccessible(origTargetNode->OwnerDoc());
287 NS_ASSERTION(targetDocument, "No document while accessible is in document?!");
289 Accessible* accessible =
290 targetDocument->GetAccessibleOrContainer(origTargetNode);
291 if (!accessible)
292 return;
294 #ifdef MOZ_XUL
295 XULTreeAccessible* treeAcc = accessible->AsXULTree();
296 if (treeAcc) {
297 if (eventType.EqualsLiteral("TreeRowCountChanged")) {
298 HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
299 return;
300 }
302 if (eventType.EqualsLiteral("TreeInvalidated")) {
303 HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
304 return;
305 }
306 }
307 #endif
309 if (eventType.EqualsLiteral("RadioStateChange")) {
310 uint64_t state = accessible->State();
311 bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0;
313 if (accessible->NeedsDOMUIEvent()) {
314 nsRefPtr<AccEvent> accEvent =
315 new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
316 nsEventShell::FireEvent(accEvent);
317 }
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 }
327 return;
328 }
330 if (eventType.EqualsLiteral("CheckboxStateChange")) {
331 if (accessible->NeedsDOMUIEvent()) {
332 uint64_t state = accessible->State();
333 bool isEnabled = !!(state & states::CHECKED);
335 nsRefPtr<AccEvent> accEvent =
336 new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
337 nsEventShell::FireEvent(accEvent);
338 }
339 return;
340 }
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 }
351 if (treeItemAcc && eventType.EqualsLiteral("OpenStateChange")) {
352 uint64_t state = accessible->State();
353 bool isEnabled = (state & states::EXPANDED) != 0;
355 nsRefPtr<AccEvent> accEvent =
356 new AccStateChangeEvent(accessible, states::EXPANDED, isEnabled);
357 nsEventShell::FireEvent(accEvent);
358 return;
359 }
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 }
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);
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);
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 }
467 ////////////////////////////////////////////////////////////////////////////////
468 // Accessible
470 void
471 RootAccessible::Shutdown()
472 {
473 // Called manually or by Accessible::LastRelease()
474 if (!PresShell())
475 return; // Already shutdown
477 DocAccessibleWrap::Shutdown();
478 }
480 // nsIAccessible method
481 Relation
482 RootAccessible::RelationByType(RelationType aType)
483 {
484 if (!mDocumentNode || aType != RelationType::EMBEDS)
485 return DocAccessibleWrap::RelationByType(aType);
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 }
505 return Relation();
506 }
508 ////////////////////////////////////////////////////////////////////////////////
509 // Protected members
511 void
512 RootAccessible::HandlePopupShownEvent(Accessible* aAccessible)
513 {
514 roles::Role role = aAccessible->Role();
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 }
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 }
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;
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 }
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;
559 Accessible* popup = document->GetAccessible(aPopupNode);
560 if (!popup) {
561 Accessible* popupContainer = document->GetContainerAccessible(aPopupNode);
562 if (!popupContainer)
563 return;
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 }
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 }
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.
586 static const uint32_t kNotifyOfFocus = 1;
587 static const uint32_t kNotifyOfState = 2;
588 uint32_t notifyOf = 0;
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;
602 widget = popup;
603 }
604 }
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;
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;
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 }
627 // Autocomplete (like searchbar) can be inactive when popup hiddens
628 notifyOf |= kNotifyOfFocus;
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 }
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 }
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 }
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;
665 nsCOMPtr<nsIVariant> detailVariant;
666 customEvent->GetDetail(getter_AddRefs(detailVariant));
667 if (!detailVariant)
668 return;
670 nsCOMPtr<nsISupports> supports;
671 detailVariant->GetAsISupports(getter_AddRefs(supports));
672 nsCOMPtr<nsIPropertyBag2> propBag(do_QueryInterface(supports));
673 if (!propBag)
674 return;
676 nsresult rv;
677 int32_t index, count;
678 rv = propBag->GetPropertyAsInt32(NS_LITERAL_STRING("index"), &index);
679 if (NS_FAILED(rv))
680 return;
682 rv = propBag->GetPropertyAsInt32(NS_LITERAL_STRING("count"), &count);
683 if (NS_FAILED(rv))
684 return;
686 aAccessible->InvalidateCache(index, count);
687 }
689 void
690 RootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
691 XULTreeAccessible* aAccessible)
692 {
693 nsCOMPtr<nsIDOMCustomEvent> customEvent(do_QueryInterface(aEvent));
694 if (!customEvent)
695 return;
697 nsCOMPtr<nsIVariant> detailVariant;
698 customEvent->GetDetail(getter_AddRefs(detailVariant));
699 if (!detailVariant)
700 return;
702 nsCOMPtr<nsISupports> supports;
703 detailVariant->GetAsISupports(getter_AddRefs(supports));
704 nsCOMPtr<nsIPropertyBag2> propBag(do_QueryInterface(supports));
705 if (!propBag)
706 return;
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);
718 aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
719 }
720 #endif