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"
9 #include "mozilla/PresShell.h" // for nsAccUtils::GetDocAccessibleFor()
11 #define CreateEvent CreateEventA
13 #include "LocalAccessible-inl.h"
14 #include "DocAccessible-inl.h"
15 #include "mozilla/a11y/DocAccessibleParent.h"
16 #include "nsAccessibilityService.h"
17 #include "nsAccUtils.h"
18 #include "nsCoreUtils.h"
19 #include "nsEventShell.h"
24 # include "XULTreeAccessible.h"
27 #include "mozilla/dom/BindingUtils.h"
28 #include "mozilla/dom/CustomEvent.h"
29 #include "mozilla/dom/Element.h"
30 #include "mozilla/dom/ScriptSettings.h"
31 #include "mozilla/dom/BrowserHost.h"
33 #include "nsIDocShellTreeOwner.h"
34 #include "mozilla/dom/Event.h"
35 #include "mozilla/dom/EventTarget.h"
36 #include "nsIDOMXULMultSelectCntrlEl.h"
37 #include "mozilla/dom/Document.h"
38 #include "nsIInterfaceRequestorUtils.h"
39 #include "nsIPropertyBag2.h"
40 #include "nsPIDOMWindow.h"
41 #include "nsIWebBrowserChrome.h"
42 #include "nsReadableUtils.h"
43 #include "nsFocusManager.h"
44 #include "nsGlobalWindow.h"
47 # include "nsIAppWindow.h"
50 using namespace mozilla
;
51 using namespace mozilla::a11y
;
52 using namespace mozilla::dom
;
54 ////////////////////////////////////////////////////////////////////////////////
57 NS_IMPL_ISUPPORTS_INHERITED(RootAccessible
, DocAccessible
, nsIDOMEventListener
)
59 ////////////////////////////////////////////////////////////////////////////////
60 // Constructor/destructor
62 RootAccessible::RootAccessible(Document
* aDocument
, PresShell
* aPresShell
)
63 : DocAccessibleWrap(aDocument
, aPresShell
) {
67 RootAccessible::~RootAccessible() {}
69 ////////////////////////////////////////////////////////////////////////////////
72 ENameValueFlag
RootAccessible::Name(nsString
& aName
) const {
76 LocalAccessible::Name(aName
);
77 if (!aName
.IsEmpty()) return eNameOK
;
80 mDocumentNode
->GetTitle(aName
);
84 // RootAccessible protected member
86 uint32_t RootAccessible::GetChromeFlags() const {
87 // Return the flag set for the top level window as defined
88 // by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
89 // Not simple: nsIAppWindow is not just a QI from nsIDOMWindow
90 nsCOMPtr
<nsIDocShell
> docShell
= nsCoreUtils::GetDocShellFor(mDocumentNode
);
91 NS_ENSURE_TRUE(docShell
, 0);
92 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
93 docShell
->GetTreeOwner(getter_AddRefs(treeOwner
));
94 NS_ENSURE_TRUE(treeOwner
, 0);
95 nsCOMPtr
<nsIAppWindow
> appWin(do_GetInterface(treeOwner
));
100 appWin
->GetChromeFlags(&chromeFlags
);
105 uint64_t RootAccessible::NativeState() const {
106 uint64_t state
= DocAccessibleWrap::NativeState();
107 if (state
& states::DEFUNCT
) return state
;
110 uint32_t chromeFlags
= GetChromeFlags();
111 if (chromeFlags
& nsIWebBrowserChrome::CHROME_WINDOW_RESIZE
) {
112 state
|= states::SIZEABLE
;
114 // If it has a titlebar it's movable
115 // XXX unless it's minimized or maximized, but not sure
116 // how to detect that
117 if (chromeFlags
& nsIWebBrowserChrome::CHROME_TITLEBAR
) {
118 state
|= states::MOVEABLE
;
120 if (chromeFlags
& nsIWebBrowserChrome::CHROME_MODAL
) state
|= states::MODAL
;
123 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
124 if (fm
&& fm
->GetActiveWindow() == mDocumentNode
->GetWindow()) {
125 state
|= states::ACTIVE
;
131 const char* const kEventTypes
[] = {
132 #ifdef DEBUG_DRAGDROPSTART
133 // Capture mouse over events and fire fake DRAGDROPSTART event to simplify
134 // debugging a11y objects with event viewers.
137 // Fired when list or tree selection changes.
139 // Fired when value changes immediately, wether or not focused changed.
140 "ValueChange", "AlertActive", "TreeRowCountChanged", "TreeInvalidated",
141 // add ourself as a OpenStateChange listener (custom event fired in
144 // add ourself as a CheckboxStateChange listener (custom event fired in
145 // HTMLInputElement.cpp)
146 "CheckboxStateChange",
147 // add ourself as a RadioStateChange Listener (custom event fired in in
148 // HTMLInputElement.cpp & radio.js)
149 "RadioStateChange", "popupshown", "popuphiding", "DOMMenuInactive",
150 "DOMMenuItemActive", "DOMMenuItemInactive", "DOMMenuBarActive",
151 "DOMMenuBarInactive", "scroll"};
153 nsresult
RootAccessible::AddEventListeners() {
154 // EventTarget interface allows to register event listeners to
155 // receive untrusted events (synthetic events generated by untrusted code).
156 // For example, XBL bindings implementations for elements that are hosted in
157 // non chrome document fire untrusted events.
158 // We must use the window's parent target in order to receive events from
159 // iframes and shadow DOM; e.g. ValueChange events from a <select> in an
160 // iframe or shadow DOM. The root document itself doesn't receive these.
161 nsPIDOMWindowOuter
* window
= mDocumentNode
->GetWindow();
162 nsCOMPtr
<EventTarget
> nstarget
= window
? window
->GetParentTarget() : nullptr;
165 for (const char *const *e
= kEventTypes
, *const *e_end
=
166 ArrayEnd(kEventTypes
);
168 nsresult rv
= nstarget
->AddEventListener(NS_ConvertASCIItoUTF16(*e
), this,
170 NS_ENSURE_SUCCESS(rv
, rv
);
174 return DocAccessible::AddEventListeners();
177 nsresult
RootAccessible::RemoveEventListeners() {
178 nsPIDOMWindowOuter
* window
= mDocumentNode
->GetWindow();
179 nsCOMPtr
<EventTarget
> target
= window
? window
->GetParentTarget() : nullptr;
181 for (const char *const *e
= kEventTypes
, *const *e_end
=
182 ArrayEnd(kEventTypes
);
184 target
->RemoveEventListener(NS_ConvertASCIItoUTF16(*e
), this, true);
188 // Do this before removing clearing caret accessible, so that it can use
189 // shutdown the caret accessible's selection listener
190 DocAccessible::RemoveEventListeners();
194 ////////////////////////////////////////////////////////////////////////////////
197 void RootAccessible::DocumentActivated(DocAccessible
* aDocument
) {}
199 ////////////////////////////////////////////////////////////////////////////////
200 // nsIDOMEventListener
203 RootAccessible::HandleEvent(Event
* aDOMEvent
) {
204 MOZ_ASSERT(aDOMEvent
);
206 // Even though we've been shut down, RemoveEventListeners might not have
207 // removed the event handlers on the window's parent target if GetWindow
208 // returned null, so we might still get events here in this case. We should
209 // just ignore these events.
213 nsCOMPtr
<nsINode
> origTargetNode
=
214 do_QueryInterface(aDOMEvent
->GetOriginalTarget());
215 if (!origTargetNode
) return NS_OK
;
218 if (logging::IsEnabled(logging::eDOMEvents
)) {
219 nsAutoString eventType
;
220 aDOMEvent
->GetType(eventType
);
221 logging::DOMEvent("handled", origTargetNode
, eventType
);
225 DocAccessible
* document
=
226 GetAccService()->GetDocAccessible(origTargetNode
->OwnerDoc());
229 nsAutoString eventType
;
230 aDOMEvent
->GetType(eventType
);
231 if (eventType
.EqualsLiteral("scroll")) {
232 // We don't put this in the notification queue for 2 reasons:
233 // 1. We will flood the queue with repetitive events.
234 // 2. Since this doesn't necessarily touch layout, we are not
235 // guaranteed to have a WillRefresh tick any time soon.
236 document
->HandleScroll(origTargetNode
);
238 // Root accessible exists longer than any of its descendant documents so
239 // that we are guaranteed notification is processed before root accessible
241 // For shadow DOM, GetOriginalTarget on the Event returns null if we
242 // process the event async, so we must pass the target node as well.
243 document
->HandleNotification
<RootAccessible
, Event
, nsINode
>(
244 this, &RootAccessible::ProcessDOMEvent
, aDOMEvent
, origTargetNode
);
251 // RootAccessible protected
252 void RootAccessible::ProcessDOMEvent(Event
* aDOMEvent
, nsINode
* aTarget
) {
253 MOZ_ASSERT(aDOMEvent
);
256 nsAutoString eventType
;
257 aDOMEvent
->GetType(eventType
);
260 if (logging::IsEnabled(logging::eDOMEvents
)) {
261 logging::DOMEvent("processed", aTarget
, eventType
);
265 if (eventType
.EqualsLiteral("popuphiding")) {
266 HandlePopupHidingEvent(aTarget
);
270 DocAccessible
* targetDocument
=
271 GetAccService()->GetDocAccessible(aTarget
->OwnerDoc());
272 if (!targetDocument
) {
273 // Document has ceased to exist.
277 if (eventType
.EqualsLiteral("popupshown") &&
278 (aTarget
->IsXULElement(nsGkAtoms::tooltip
) ||
279 aTarget
->IsXULElement(nsGkAtoms::panel
))) {
280 targetDocument
->ContentInserted(aTarget
->AsContent(),
281 aTarget
->GetNextSibling());
285 LocalAccessible
* accessible
=
286 targetDocument
->GetAccessibleOrContainer(aTarget
);
287 if (!accessible
) return;
290 XULTreeAccessible
* treeAcc
= accessible
->AsXULTree();
292 if (eventType
.EqualsLiteral("TreeRowCountChanged")) {
293 HandleTreeRowCountChangedEvent(aDOMEvent
, treeAcc
);
297 if (eventType
.EqualsLiteral("TreeInvalidated")) {
298 HandleTreeInvalidatedEvent(aDOMEvent
, treeAcc
);
304 if (eventType
.EqualsLiteral("RadioStateChange")) {
305 uint64_t state
= accessible
->State();
306 bool isEnabled
= (state
& (states::CHECKED
| states::SELECTED
)) != 0;
308 if (accessible
->NeedsDOMUIEvent()) {
309 RefPtr
<AccEvent
> accEvent
=
310 new AccStateChangeEvent(accessible
, states::CHECKED
, isEnabled
);
311 nsEventShell::FireEvent(accEvent
);
315 FocusMgr()->ActiveItemChanged(accessible
);
317 if (logging::IsEnabled(logging::eFocus
)) {
318 logging::ActiveItemChangeCausedBy("RadioStateChange", accessible
);
326 if (eventType
.EqualsLiteral("CheckboxStateChange")) {
327 if (accessible
->NeedsDOMUIEvent()) {
328 uint64_t state
= accessible
->State();
329 bool isEnabled
= !!(state
& states::CHECKED
);
331 RefPtr
<AccEvent
> accEvent
=
332 new AccStateChangeEvent(accessible
, states::CHECKED
, isEnabled
);
333 nsEventShell::FireEvent(accEvent
);
338 LocalAccessible
* treeItemAcc
= nullptr;
340 // If it's a tree element, need the currently selected item.
342 treeItemAcc
= accessible
->CurrentItem();
343 if (treeItemAcc
) accessible
= treeItemAcc
;
346 if (treeItemAcc
&& eventType
.EqualsLiteral("OpenStateChange")) {
347 uint64_t state
= accessible
->State();
348 bool isEnabled
= (state
& states::EXPANDED
) != 0;
350 RefPtr
<AccEvent
> accEvent
=
351 new AccStateChangeEvent(accessible
, states::EXPANDED
, isEnabled
);
352 nsEventShell::FireEvent(accEvent
);
356 nsINode
* targetNode
= accessible
->GetNode();
357 if (treeItemAcc
&& eventType
.EqualsLiteral("select")) {
358 // XXX: We shouldn't be based on DOM select event which doesn't provide us
359 // any context info. We should integrate into nsTreeSelection instead.
360 // If multiselect tree, we should fire selectionadd or selection removed
361 if (FocusMgr()->HasDOMFocus(targetNode
)) {
362 nsCOMPtr
<nsIDOMXULMultiSelectControlElement
> multiSel
=
363 targetNode
->AsElement()->AsXULMultiSelectControl();
365 // This shouldn't be possible. All XUL trees should have
366 // nsIDOMXULMultiSelectControlElement, and the tree is focused, so it
367 // shouldn't be dying. Nevertheless, this sometimes happens in the wild
369 MOZ_ASSERT_UNREACHABLE(
370 "XUL tree doesn't have nsIDOMXULMultiSelectControlElement");
373 nsAutoString selType
;
374 multiSel
->GetSelType(selType
);
375 if (selType
.IsEmpty() || !selType
.EqualsLiteral("single")) {
376 // XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
377 // for each tree item. Perhaps each tree item will need to cache its
378 // selection state and fire an event after a DOM "select" event when
379 // that state changes. XULTreeAccessible::UpdateTreeSelection();
380 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN
,
385 RefPtr
<AccSelChangeEvent
> selChangeEvent
= new AccSelChangeEvent(
386 treeAcc
, treeItemAcc
, AccSelChangeEvent::eSelectionAdd
);
387 nsEventShell::FireEvent(selChangeEvent
);
392 if (eventType
.EqualsLiteral("AlertActive")) {
393 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT
, accessible
);
394 } else if (eventType
.EqualsLiteral("popupshown")) {
395 HandlePopupShownEvent(accessible
);
396 } else if (eventType
.EqualsLiteral("DOMMenuInactive")) {
397 if (accessible
->Role() == roles::MENUPOPUP
) {
398 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END
,
401 } else if (eventType
.EqualsLiteral("DOMMenuItemActive")) {
402 FocusMgr()->ActiveItemChanged(accessible
);
404 if (logging::IsEnabled(logging::eFocus
)) {
405 logging::ActiveItemChangeCausedBy("DOMMenuItemActive", accessible
);
408 } else if (eventType
.EqualsLiteral("DOMMenuItemInactive")) {
409 // Process DOMMenuItemInactive event for autocomplete only because this is
410 // unique widget that may acquire focus from autocomplete popup while popup
411 // stays open and has no active item. In case of XUL tree autocomplete
412 // popup this event is fired for tree accessible.
413 LocalAccessible
* widget
=
414 accessible
->IsWidget() ? accessible
: accessible
->ContainerWidget();
415 if (widget
&& widget
->IsAutoCompletePopup()) {
416 FocusMgr()->ActiveItemChanged(nullptr);
418 if (logging::IsEnabled(logging::eFocus
)) {
419 logging::ActiveItemChangeCausedBy("DOMMenuItemInactive", accessible
);
423 } else if (eventType
.EqualsLiteral(
424 "DOMMenuBarActive")) { // Always from user input
425 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START
, accessible
,
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 LocalAccessible
* activeItem
= accessible
->CurrentItem();
436 FocusMgr()->ActiveItemChanged(activeItem
);
438 if (logging::IsEnabled(logging::eFocus
)) {
439 logging::ActiveItemChangeCausedBy("DOMMenuBarActive", accessible
);
443 } else if (eventType
.EqualsLiteral(
444 "DOMMenuBarInactive")) { // Always from user input
445 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END
, accessible
,
448 FocusMgr()->ActiveItemChanged(nullptr);
450 if (logging::IsEnabled(logging::eFocus
)) {
451 logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible
);
454 } else if (accessible
->NeedsDOMUIEvent() &&
455 eventType
.EqualsLiteral("ValueChange")) {
456 uint32_t event
= accessible
->HasNumericValue()
457 ? nsIAccessibleEvent::EVENT_VALUE_CHANGE
458 : nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE
;
459 targetDocument
->FireDelayedEvent(event
, accessible
);
461 #ifdef DEBUG_DRAGDROPSTART
462 else if (eventType
.EqualsLiteral("mouseover")) {
463 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START
,
469 ////////////////////////////////////////////////////////////////////////////////
472 void RootAccessible::Shutdown() {
473 // Called manually or by LocalAccessible::LastRelease()
477 DocAccessibleWrap::Shutdown();
480 Relation
RootAccessible::RelationByType(RelationType aType
) const {
481 if (!mDocumentNode
|| aType
!= RelationType::EMBEDS
) {
482 return DocAccessibleWrap::RelationByType(aType
);
485 if (nsIDocShell
* docShell
= mDocumentNode
->GetDocShell()) {
486 nsCOMPtr
<nsIDocShellTreeOwner
> owner
;
487 docShell
->GetTreeOwner(getter_AddRefs(owner
));
489 nsCOMPtr
<nsIDocShellTreeItem
> contentShell
;
490 owner
->GetPrimaryContentShell(getter_AddRefs(contentShell
));
492 return Relation(nsAccUtils::GetDocAccessibleFor(contentShell
));
500 ////////////////////////////////////////////////////////////////////////////////
503 void RootAccessible::HandlePopupShownEvent(LocalAccessible
* aAccessible
) {
504 roles::Role role
= aAccessible
->Role();
506 if (role
== roles::MENUPOPUP
) {
507 // Don't fire menupopup events for combobox and autocomplete lists.
508 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START
,
513 if (role
== roles::COMBOBOX_LIST
) {
514 // Fire expanded state change event for comboboxes and autocompeletes.
515 LocalAccessible
* combobox
= aAccessible
->LocalParent();
516 if (!combobox
) return;
518 if (combobox
->IsCombobox() || combobox
->IsAutoComplete()) {
519 RefPtr
<AccEvent
> event
=
520 new AccStateChangeEvent(combobox
, states::EXPANDED
, true);
521 nsEventShell::FireEvent(event
);
524 // If aria-activedescendant is present, redirect focus.
525 // This is needed for parent process <select> dropdowns, which use a
526 // menulist containing div elements instead of XUL menuitems. XUL menuitems
527 // fire DOMMenuItemActive events from layout instead.
528 MOZ_ASSERT(aAccessible
->Elm());
529 if (aAccessible
->Elm()->HasAttr(kNameSpaceID_None
,
530 nsGkAtoms::aria_activedescendant
)) {
531 LocalAccessible
* activeDescendant
= aAccessible
->CurrentItem();
532 if (activeDescendant
) {
533 FocusMgr()->ActiveItemChanged(activeDescendant
, false);
535 if (logging::IsEnabled(logging::eFocus
)) {
536 logging::ActiveItemChangeCausedBy("ARIA activedescendant on popup",
545 void RootAccessible::HandlePopupHidingEvent(nsINode
* aPopupNode
) {
546 DocAccessible
* document
= nsAccUtils::GetDocAccessibleFor(aPopupNode
);
547 if (!document
) return;
549 if (aPopupNode
->IsXULElement(nsGkAtoms::tooltip
) ||
550 aPopupNode
->IsXULElement(nsGkAtoms::panel
)) {
551 document
->ContentRemoved(aPopupNode
->AsContent());
555 // Get popup accessible. There are cases when popup element isn't accessible
556 // but an underlying widget is and behaves like popup, an example is
557 // autocomplete popups.
558 LocalAccessible
* popup
= document
->GetAccessible(aPopupNode
);
560 LocalAccessible
* popupContainer
=
561 document
->GetContainerAccessible(aPopupNode
);
562 if (!popupContainer
) return;
564 uint32_t childCount
= popupContainer
->ChildCount();
565 for (uint32_t idx
= 0; idx
< childCount
; idx
++) {
566 LocalAccessible
* child
= popupContainer
->LocalChildAt(idx
);
567 if (child
->IsAutoCompletePopup()) {
573 // No popup no events. Focus is managed by DOM. This is a case for
574 // menupopups of menus on Linux since there are no accessible for popups.
578 // In case of autocompletes and comboboxes fire state change event for
579 // expanded state. Note, HTML form autocomplete isn't a subject of state
580 // change event because they aren't autocompletes strictly speaking.
581 // When popup closes (except nested popups and menus) then fire focus event to
582 // where it was. The focus event is expected even if popup didn't take a
585 static const uint32_t kNotifyOfFocus
= 1;
586 static const uint32_t kNotifyOfState
= 2;
587 uint32_t notifyOf
= 0;
589 // HTML select is target of popuphidding event. Otherwise get container
590 // widget. No container widget means this is either tooltip or menupopup.
591 // No events in the former case.
592 LocalAccessible
* widget
= nullptr;
593 if (popup
->IsCombobox()) {
596 widget
= popup
->ContainerWidget();
598 if (!popup
->IsMenuPopup()) return;
604 if (popup
->IsAutoCompletePopup()) {
605 // No focus event for autocomplete because it's managed by
606 // DOMMenuItemInactive events.
607 if (widget
->IsAutoComplete()) notifyOf
= kNotifyOfState
;
609 } else if (widget
->IsCombobox()) {
610 // Fire focus for active combobox, otherwise the focus is managed by DOM
611 // focus notifications. Always fire state change event.
612 if (widget
->IsActiveWidget()) notifyOf
= kNotifyOfFocus
;
613 notifyOf
|= kNotifyOfState
;
615 } else if (widget
->IsMenuButton()) {
616 // Can be a part of autocomplete.
617 LocalAccessible
* compositeWidget
= widget
->ContainerWidget();
618 if (compositeWidget
&& compositeWidget
->IsAutoComplete()) {
619 widget
= compositeWidget
;
620 notifyOf
= kNotifyOfState
;
623 // Autocomplete (like searchbar) can be inactive when popup hiddens
624 notifyOf
|= kNotifyOfFocus
;
626 } else if (widget
== popup
) {
627 // Top level context menus and alerts.
628 // Ignore submenus and menubar. When submenu is closed then sumbenu
629 // container menuitem takes a focus via DOMMenuItemActive notification.
630 // For menubars processing we listen DOMMenubarActive/Inactive
632 notifyOf
= kNotifyOfFocus
;
635 // Restore focus to where it was.
636 if (notifyOf
& kNotifyOfFocus
) {
637 FocusMgr()->ActiveItemChanged(nullptr);
639 if (logging::IsEnabled(logging::eFocus
)) {
640 logging::ActiveItemChangeCausedBy("popuphiding", popup
);
645 // Fire expanded state change event.
646 if (notifyOf
& kNotifyOfState
) {
647 RefPtr
<AccEvent
> event
=
648 new AccStateChangeEvent(widget
, states::EXPANDED
, false);
649 document
->FireDelayedEvent(event
);
654 static void GetPropertyBagFromEvent(Event
* aEvent
,
655 nsIPropertyBag2
** aPropertyBag
) {
656 *aPropertyBag
= nullptr;
658 CustomEvent
* customEvent
= aEvent
->AsCustomEvent();
659 if (!customEvent
) return;
662 if (!jsapi
.Init(customEvent
->GetParentObject())) return;
664 JSContext
* cx
= jsapi
.cx();
665 JS::Rooted
<JS::Value
> detail(cx
);
666 customEvent
->GetDetail(cx
, &detail
);
667 if (!detail
.isObject()) return;
669 JS::Rooted
<JSObject
*> detailObj(cx
, &detail
.toObject());
672 nsCOMPtr
<nsIPropertyBag2
> propBag
;
673 rv
= UnwrapArg
<nsIPropertyBag2
>(cx
, detailObj
, getter_AddRefs(propBag
));
674 if (NS_FAILED(rv
)) return;
676 propBag
.forget(aPropertyBag
);
679 void RootAccessible::HandleTreeRowCountChangedEvent(
680 Event
* aEvent
, XULTreeAccessible
* aAccessible
) {
681 nsCOMPtr
<nsIPropertyBag2
> propBag
;
682 GetPropertyBagFromEvent(aEvent
, getter_AddRefs(propBag
));
683 if (!propBag
) return;
686 int32_t index
, count
;
687 rv
= propBag
->GetPropertyAsInt32(u
"index"_ns
, &index
);
688 if (NS_FAILED(rv
)) return;
690 rv
= propBag
->GetPropertyAsInt32(u
"count"_ns
, &count
);
691 if (NS_FAILED(rv
)) return;
693 aAccessible
->InvalidateCache(index
, count
);
696 void RootAccessible::HandleTreeInvalidatedEvent(
697 Event
* aEvent
, XULTreeAccessible
* aAccessible
) {
698 nsCOMPtr
<nsIPropertyBag2
> propBag
;
699 GetPropertyBagFromEvent(aEvent
, getter_AddRefs(propBag
));
700 if (!propBag
) return;
702 int32_t startRow
= 0, endRow
= -1, startCol
= 0, endCol
= -1;
703 propBag
->GetPropertyAsInt32(u
"startrow"_ns
, &startRow
);
704 propBag
->GetPropertyAsInt32(u
"endrow"_ns
, &endRow
);
705 propBag
->GetPropertyAsInt32(u
"startcolumn"_ns
, &startCol
);
706 propBag
->GetPropertyAsInt32(u
"endcolumn"_ns
, &endCol
);
708 aAccessible
->TreeViewInvalidated(startRow
, endRow
, startCol
, endCol
);
712 RemoteAccessible
* RootAccessible::GetPrimaryRemoteTopLevelContentDoc() const {
713 nsCOMPtr
<nsIDocShellTreeOwner
> owner
;
714 mDocumentNode
->GetDocShell()->GetTreeOwner(getter_AddRefs(owner
));
715 NS_ENSURE_TRUE(owner
, nullptr);
717 nsCOMPtr
<nsIRemoteTab
> remoteTab
;
718 owner
->GetPrimaryRemoteTab(getter_AddRefs(remoteTab
));
723 auto tab
= static_cast<dom::BrowserHost
*>(remoteTab
.get());
724 return tab
->GetTopLevelDocAccessible();