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"
23 #include "XULTreeAccessible.h"
25 #include "mozilla/dom/BindingUtils.h"
26 #include "mozilla/dom/CustomEvent.h"
27 #include "mozilla/dom/Element.h"
28 #include "mozilla/dom/ScriptSettings.h"
29 #include "mozilla/dom/BrowserHost.h"
31 #include "nsIDocShellTreeOwner.h"
32 #include "mozilla/dom/Event.h"
33 #include "mozilla/dom/EventTarget.h"
34 #include "nsIDOMXULMultSelectCntrlEl.h"
35 #include "mozilla/dom/Document.h"
36 #include "nsIInterfaceRequestorUtils.h"
37 #include "nsIPropertyBag2.h"
38 #include "nsPIDOMWindow.h"
39 #include "nsIWebBrowserChrome.h"
40 #include "nsReadableUtils.h"
41 #include "nsFocusManager.h"
42 #include "nsGlobalWindow.h"
44 #include "nsIAppWindow.h"
46 using namespace mozilla
;
47 using namespace mozilla::a11y
;
48 using namespace mozilla::dom
;
50 ////////////////////////////////////////////////////////////////////////////////
53 NS_IMPL_ISUPPORTS_INHERITED(RootAccessible
, DocAccessible
, nsIDOMEventListener
)
55 ////////////////////////////////////////////////////////////////////////////////
56 // Constructor/destructor
58 RootAccessible::RootAccessible(Document
* aDocument
, PresShell
* aPresShell
)
59 : DocAccessibleWrap(aDocument
, aPresShell
) {
63 RootAccessible::~RootAccessible() {}
65 ////////////////////////////////////////////////////////////////////////////////
68 ENameValueFlag
RootAccessible::Name(nsString
& aName
) const {
72 LocalAccessible::Name(aName
);
73 if (!aName
.IsEmpty()) return eNameOK
;
76 mDocumentNode
->GetTitle(aName
);
80 // RootAccessible protected member
81 uint32_t RootAccessible::GetChromeFlags() const {
82 // Return the flag set for the top level window as defined
83 // by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
84 // Not simple: nsIAppWindow is not just a QI from nsIDOMWindow
85 nsCOMPtr
<nsIDocShell
> docShell
= nsCoreUtils::GetDocShellFor(mDocumentNode
);
86 NS_ENSURE_TRUE(docShell
, 0);
87 nsCOMPtr
<nsIDocShellTreeOwner
> treeOwner
;
88 docShell
->GetTreeOwner(getter_AddRefs(treeOwner
));
89 NS_ENSURE_TRUE(treeOwner
, 0);
90 nsCOMPtr
<nsIAppWindow
> appWin(do_GetInterface(treeOwner
));
95 appWin
->GetChromeFlags(&chromeFlags
);
99 uint64_t RootAccessible::NativeState() const {
100 uint64_t state
= DocAccessibleWrap::NativeState();
101 if (state
& states::DEFUNCT
) return state
;
103 uint32_t chromeFlags
= GetChromeFlags();
104 if (chromeFlags
& nsIWebBrowserChrome::CHROME_WINDOW_RESIZE
) {
105 state
|= states::SIZEABLE
;
107 // If it has a titlebar it's movable
108 // XXX unless it's minimized or maximized, but not sure
109 // how to detect that
110 if (chromeFlags
& nsIWebBrowserChrome::CHROME_TITLEBAR
) {
111 state
|= states::MOVEABLE
;
113 if (chromeFlags
& nsIWebBrowserChrome::CHROME_MODAL
) state
|= states::MODAL
;
115 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
116 if (fm
&& fm
->GetActiveWindow() == mDocumentNode
->GetWindow()) {
117 state
|= states::ACTIVE
;
123 const char* const kEventTypes
[] = {
124 #ifdef DEBUG_DRAGDROPSTART
125 // Capture mouse over events and fire fake DRAGDROPSTART event to simplify
126 // debugging a11y objects with event viewers.
129 // Fired when list or tree selection changes.
131 // Fired when value changes immediately, wether or not focused changed.
132 "ValueChange", "AlertActive", "TreeRowCountChanged", "TreeInvalidated",
133 // add ourself as a OpenStateChange listener (custom event fired in
136 // add ourself as a CheckboxStateChange listener (custom event fired in
137 // HTMLInputElement.cpp)
138 "CheckboxStateChange",
139 // add ourself as a RadioStateChange Listener (custom event fired in in
140 // HTMLInputElement.cpp & radio.js)
141 "RadioStateChange", "popupshown", "popuphiding", "DOMMenuInactive",
142 "DOMMenuItemActive", "DOMMenuItemInactive", "DOMMenuBarActive",
143 "DOMMenuBarInactive", "scroll"};
145 nsresult
RootAccessible::AddEventListeners() {
146 // EventTarget interface allows to register event listeners to
147 // receive untrusted events (synthetic events generated by untrusted code).
148 // For example, XBL bindings implementations for elements that are hosted in
149 // non chrome document fire untrusted events.
150 // We must use the window's parent target in order to receive events from
151 // iframes and shadow DOM; e.g. ValueChange events from a <select> in an
152 // iframe or shadow DOM. The root document itself doesn't receive these.
153 nsPIDOMWindowOuter
* window
= mDocumentNode
->GetWindow();
154 nsCOMPtr
<EventTarget
> nstarget
= window
? window
->GetParentTarget() : nullptr;
157 for (const char *const *e
= kEventTypes
, *const *e_end
=
158 ArrayEnd(kEventTypes
);
160 nsresult rv
= nstarget
->AddEventListener(NS_ConvertASCIItoUTF16(*e
), this,
162 NS_ENSURE_SUCCESS(rv
, rv
);
166 return DocAccessible::AddEventListeners();
169 nsresult
RootAccessible::RemoveEventListeners() {
170 nsPIDOMWindowOuter
* window
= mDocumentNode
->GetWindow();
171 nsCOMPtr
<EventTarget
> target
= window
? window
->GetParentTarget() : nullptr;
173 for (const char *const *e
= kEventTypes
, *const *e_end
=
174 ArrayEnd(kEventTypes
);
176 target
->RemoveEventListener(NS_ConvertASCIItoUTF16(*e
), this, true);
180 // Do this before removing clearing caret accessible, so that it can use
181 // shutdown the caret accessible's selection listener
182 DocAccessible::RemoveEventListeners();
186 ////////////////////////////////////////////////////////////////////////////////
189 void RootAccessible::DocumentActivated(DocAccessible
* aDocument
) {}
191 ////////////////////////////////////////////////////////////////////////////////
192 // nsIDOMEventListener
195 RootAccessible::HandleEvent(Event
* aDOMEvent
) {
196 MOZ_ASSERT(aDOMEvent
);
198 // Even though we've been shut down, RemoveEventListeners might not have
199 // removed the event handlers on the window's parent target if GetWindow
200 // returned null, so we might still get events here in this case. We should
201 // just ignore these events.
205 nsCOMPtr
<nsINode
> origTargetNode
=
206 do_QueryInterface(aDOMEvent
->GetOriginalTarget());
207 if (!origTargetNode
) return NS_OK
;
210 if (logging::IsEnabled(logging::eDOMEvents
)) {
211 nsAutoString eventType
;
212 aDOMEvent
->GetType(eventType
);
213 logging::DOMEvent("handled", origTargetNode
, eventType
);
217 DocAccessible
* document
=
218 GetAccService()->GetDocAccessible(origTargetNode
->OwnerDoc());
221 nsAutoString eventType
;
222 aDOMEvent
->GetType(eventType
);
223 if (eventType
.EqualsLiteral("scroll")) {
224 // We don't put this in the notification queue for 2 reasons:
225 // 1. We will flood the queue with repetitive events.
226 // 2. Since this doesn't necessarily touch layout, we are not
227 // guaranteed to have a WillRefresh tick any time soon.
228 document
->HandleScroll(origTargetNode
);
230 // Root accessible exists longer than any of its descendant documents so
231 // that we are guaranteed notification is processed before root accessible
233 // For shadow DOM, GetOriginalTarget on the Event returns null if we
234 // process the event async, so we must pass the target node as well.
235 document
->HandleNotification
<RootAccessible
, Event
, nsINode
>(
236 this, &RootAccessible::ProcessDOMEvent
, aDOMEvent
, origTargetNode
);
243 // RootAccessible protected
244 void RootAccessible::ProcessDOMEvent(Event
* aDOMEvent
, nsINode
* aTarget
) {
245 MOZ_ASSERT(aDOMEvent
);
248 nsAutoString eventType
;
249 aDOMEvent
->GetType(eventType
);
252 if (logging::IsEnabled(logging::eDOMEvents
)) {
253 logging::DOMEvent("processed", aTarget
, eventType
);
257 if (eventType
.EqualsLiteral("popuphiding")) {
258 HandlePopupHidingEvent(aTarget
);
262 DocAccessible
* targetDocument
=
263 GetAccService()->GetDocAccessible(aTarget
->OwnerDoc());
264 if (!targetDocument
) {
265 // Document has ceased to exist.
269 if (eventType
.EqualsLiteral("popupshown") &&
270 (aTarget
->IsXULElement(nsGkAtoms::tooltip
) ||
271 aTarget
->IsXULElement(nsGkAtoms::panel
))) {
272 targetDocument
->ContentInserted(aTarget
->AsContent(),
273 aTarget
->GetNextSibling());
277 LocalAccessible
* accessible
=
278 targetDocument
->GetAccessibleOrContainer(aTarget
);
279 if (!accessible
) return;
281 XULTreeAccessible
* treeAcc
= accessible
->AsXULTree();
283 if (eventType
.EqualsLiteral("TreeRowCountChanged")) {
284 HandleTreeRowCountChangedEvent(aDOMEvent
, treeAcc
);
288 if (eventType
.EqualsLiteral("TreeInvalidated")) {
289 HandleTreeInvalidatedEvent(aDOMEvent
, treeAcc
);
294 if (eventType
.EqualsLiteral("RadioStateChange")) {
295 uint64_t state
= accessible
->State();
296 bool isEnabled
= (state
& (states::CHECKED
| states::SELECTED
)) != 0;
298 if (accessible
->NeedsDOMUIEvent()) {
299 RefPtr
<AccEvent
> accEvent
=
300 new AccStateChangeEvent(accessible
, states::CHECKED
, isEnabled
);
301 nsEventShell::FireEvent(accEvent
);
305 FocusMgr()->ActiveItemChanged(accessible
);
307 if (logging::IsEnabled(logging::eFocus
)) {
308 logging::ActiveItemChangeCausedBy("RadioStateChange", accessible
);
316 if (eventType
.EqualsLiteral("CheckboxStateChange")) {
317 if (accessible
->NeedsDOMUIEvent()) {
318 uint64_t state
= accessible
->State();
319 bool isEnabled
= !!(state
& states::CHECKED
);
321 RefPtr
<AccEvent
> accEvent
=
322 new AccStateChangeEvent(accessible
, states::CHECKED
, isEnabled
);
323 nsEventShell::FireEvent(accEvent
);
328 LocalAccessible
* treeItemAcc
= nullptr;
329 // If it's a tree element, need the currently selected item.
331 treeItemAcc
= accessible
->CurrentItem();
332 if (treeItemAcc
) accessible
= treeItemAcc
;
335 if (treeItemAcc
&& eventType
.EqualsLiteral("OpenStateChange")) {
336 uint64_t state
= accessible
->State();
337 bool isEnabled
= (state
& states::EXPANDED
) != 0;
339 RefPtr
<AccEvent
> accEvent
=
340 new AccStateChangeEvent(accessible
, states::EXPANDED
, isEnabled
);
341 nsEventShell::FireEvent(accEvent
);
345 nsINode
* targetNode
= accessible
->GetNode();
346 if (treeItemAcc
&& eventType
.EqualsLiteral("select")) {
347 // XXX: We shouldn't be based on DOM select event which doesn't provide us
348 // any context info. We should integrate into nsTreeSelection instead.
349 // If multiselect tree, we should fire selectionadd or selection removed
350 if (FocusMgr()->HasDOMFocus(targetNode
)) {
351 nsCOMPtr
<nsIDOMXULMultiSelectControlElement
> multiSel
=
352 targetNode
->AsElement()->AsXULMultiSelectControl();
354 // This shouldn't be possible. All XUL trees should have
355 // nsIDOMXULMultiSelectControlElement, and the tree is focused, so it
356 // shouldn't be dying. Nevertheless, this sometimes happens in the wild
358 MOZ_ASSERT_UNREACHABLE(
359 "XUL tree doesn't have nsIDOMXULMultiSelectControlElement");
362 nsAutoString selType
;
363 multiSel
->GetSelType(selType
);
364 if (selType
.IsEmpty() || !selType
.EqualsLiteral("single")) {
365 // XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
366 // for each tree item. Perhaps each tree item will need to cache its
367 // selection state and fire an event after a DOM "select" event when
368 // that state changes. XULTreeAccessible::UpdateTreeSelection();
369 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN
,
374 RefPtr
<AccSelChangeEvent
> selChangeEvent
= new AccSelChangeEvent(
375 treeAcc
, treeItemAcc
, AccSelChangeEvent::eSelectionAdd
);
376 nsEventShell::FireEvent(selChangeEvent
);
379 } else if (eventType
.EqualsLiteral("AlertActive")) {
380 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT
, accessible
);
381 } else if (eventType
.EqualsLiteral("popupshown")) {
382 HandlePopupShownEvent(accessible
);
383 } else if (eventType
.EqualsLiteral("DOMMenuInactive")) {
384 if (accessible
->Role() == roles::MENUPOPUP
) {
385 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END
,
388 } else if (eventType
.EqualsLiteral("DOMMenuItemActive")) {
389 RefPtr
<AccEvent
> event
=
390 new AccStateChangeEvent(accessible
, states::ACTIVE
, true);
391 nsEventShell::FireEvent(event
);
392 FocusMgr()->ActiveItemChanged(accessible
);
394 if (logging::IsEnabled(logging::eFocus
)) {
395 logging::ActiveItemChangeCausedBy("DOMMenuItemActive", accessible
);
398 } else if (eventType
.EqualsLiteral("DOMMenuItemInactive")) {
399 RefPtr
<AccEvent
> event
=
400 new AccStateChangeEvent(accessible
, states::ACTIVE
, false);
401 nsEventShell::FireEvent(event
);
403 // Process DOMMenuItemInactive event for autocomplete only because this is
404 // unique widget that may acquire focus from autocomplete popup while popup
405 // stays open and has no active item. In case of XUL tree autocomplete
406 // popup this event is fired for tree accessible.
407 LocalAccessible
* widget
=
408 accessible
->IsWidget() ? accessible
: accessible
->ContainerWidget();
409 if (widget
&& widget
->IsAutoCompletePopup()) {
410 FocusMgr()->ActiveItemChanged(nullptr);
412 if (logging::IsEnabled(logging::eFocus
)) {
413 logging::ActiveItemChangeCausedBy("DOMMenuItemInactive", accessible
);
417 } else if (eventType
.EqualsLiteral(
418 "DOMMenuBarActive")) { // Always from user input
419 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START
, accessible
,
422 // Notify of active item change when menubar gets active and if it has
423 // current item. This is a case of mouseover (set current menuitem) and
424 // mouse click (activate the menubar). If menubar doesn't have current item
425 // (can be a case of menubar activation from keyboard) then ignore this
426 // notification because later we'll receive DOMMenuItemActive event after
427 // current menuitem is set.
428 LocalAccessible
* activeItem
= accessible
->CurrentItem();
430 FocusMgr()->ActiveItemChanged(activeItem
);
432 if (logging::IsEnabled(logging::eFocus
)) {
433 logging::ActiveItemChangeCausedBy("DOMMenuBarActive", accessible
);
437 } else if (eventType
.EqualsLiteral(
438 "DOMMenuBarInactive")) { // Always from user input
439 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END
, accessible
,
442 FocusMgr()->ActiveItemChanged(nullptr);
444 if (logging::IsEnabled(logging::eFocus
)) {
445 logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible
);
448 } else if (accessible
->NeedsDOMUIEvent() &&
449 eventType
.EqualsLiteral("ValueChange")) {
450 uint32_t event
= accessible
->HasNumericValue()
451 ? nsIAccessibleEvent::EVENT_VALUE_CHANGE
452 : nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE
;
453 targetDocument
->FireDelayedEvent(event
, accessible
);
455 #ifdef DEBUG_DRAGDROPSTART
456 else if (eventType
.EqualsLiteral("mouseover")) {
457 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START
,
463 ////////////////////////////////////////////////////////////////////////////////
466 void RootAccessible::Shutdown() {
467 // Called manually or by LocalAccessible::LastRelease()
471 DocAccessibleWrap::Shutdown();
474 Relation
RootAccessible::RelationByType(RelationType aType
) const {
475 if (!mDocumentNode
|| aType
!= RelationType::EMBEDS
) {
476 return DocAccessibleWrap::RelationByType(aType
);
479 if (nsIDocShell
* docShell
= mDocumentNode
->GetDocShell()) {
480 nsCOMPtr
<nsIDocShellTreeOwner
> owner
;
481 docShell
->GetTreeOwner(getter_AddRefs(owner
));
483 nsCOMPtr
<nsIDocShellTreeItem
> contentShell
;
484 owner
->GetPrimaryContentShell(getter_AddRefs(contentShell
));
486 return Relation(nsAccUtils::GetDocAccessibleFor(contentShell
));
494 ////////////////////////////////////////////////////////////////////////////////
497 void RootAccessible::HandlePopupShownEvent(LocalAccessible
* aAccessible
) {
498 roles::Role role
= aAccessible
->Role();
500 if (role
== roles::MENUPOPUP
) {
501 // Don't fire menupopup events for combobox and autocomplete lists.
502 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START
,
507 if (role
== roles::COMBOBOX_LIST
) {
508 // Fire expanded state change event for comboboxes and autocompeletes.
509 LocalAccessible
* combobox
= aAccessible
->LocalParent();
510 if (!combobox
) return;
512 if (combobox
->IsCombobox()) {
513 RefPtr
<AccEvent
> event
=
514 new AccStateChangeEvent(combobox
, states::EXPANDED
, true);
515 nsEventShell::FireEvent(event
);
518 // If aria-activedescendant is present, redirect focus.
519 // This is needed for parent process <select> dropdowns, which use a
520 // menulist containing div elements instead of XUL menuitems. XUL menuitems
521 // fire DOMMenuItemActive events from layout instead.
522 MOZ_ASSERT(aAccessible
->Elm());
523 if (aAccessible
->Elm()->HasAttr(kNameSpaceID_None
,
524 nsGkAtoms::aria_activedescendant
)) {
525 LocalAccessible
* activeDescendant
= aAccessible
->CurrentItem();
526 if (activeDescendant
) {
527 FocusMgr()->ActiveItemChanged(activeDescendant
, false);
529 if (logging::IsEnabled(logging::eFocus
)) {
530 logging::ActiveItemChangeCausedBy("ARIA activedescendant on popup",
539 void RootAccessible::HandlePopupHidingEvent(nsINode
* aPopupNode
) {
540 DocAccessible
* document
= nsAccUtils::GetDocAccessibleFor(aPopupNode
);
541 if (!document
) return;
543 if (aPopupNode
->IsXULElement(nsGkAtoms::tooltip
) ||
544 aPopupNode
->IsXULElement(nsGkAtoms::panel
)) {
545 document
->ContentRemoved(aPopupNode
->AsContent());
549 // Get popup accessible. There are cases when popup element isn't accessible
550 // but an underlying widget is and behaves like popup, an example is
551 // autocomplete popups.
552 LocalAccessible
* popup
= document
->GetAccessible(aPopupNode
);
554 LocalAccessible
* popupContainer
=
555 document
->GetContainerAccessible(aPopupNode
);
556 if (!popupContainer
) return;
558 uint32_t childCount
= popupContainer
->ChildCount();
559 for (uint32_t idx
= 0; idx
< childCount
; idx
++) {
560 LocalAccessible
* child
= popupContainer
->LocalChildAt(idx
);
561 if (child
->IsAutoCompletePopup()) {
567 // No popup no events. Focus is managed by DOM. This is a case for
568 // menupopups of menus on Linux since there are no accessible for popups.
572 // In case of autocompletes and comboboxes fire state change event for
573 // expanded state. Note, HTML form autocomplete isn't a subject of state
574 // change event because they aren't autocompletes strictly speaking.
575 // When popup closes (except nested popups and menus) then fire focus event to
576 // where it was. The focus event is expected even if popup didn't take a
579 static const uint32_t kNotifyOfFocus
= 1;
580 static const uint32_t kNotifyOfState
= 2;
581 uint32_t notifyOf
= 0;
583 // HTML select is target of popuphidding event. Otherwise get container
584 // widget. No container widget means this is either tooltip or menupopup.
585 // No events in the former case.
586 LocalAccessible
* widget
= nullptr;
587 if (popup
->IsCombobox()) {
590 widget
= popup
->ContainerWidget();
592 if (!popup
->IsMenuPopup()) return;
598 if (widget
->IsCombobox()) {
599 // Fire focus for active combobox, otherwise the focus is managed by DOM
600 // focus notifications. Always fire state change event.
601 if (widget
->IsActiveWidget()) notifyOf
= kNotifyOfFocus
;
602 notifyOf
|= kNotifyOfState
;
603 } else if (widget
->IsMenuButton()) {
604 // Autocomplete (like searchbar) can be inactive when popup hiddens
605 notifyOf
|= kNotifyOfFocus
;
606 } else if (widget
== popup
) {
607 // Top level context menus and alerts.
608 // Ignore submenus and menubar. When submenu is closed then sumbenu
609 // container menuitem takes a focus via DOMMenuItemActive notification.
610 // For menubars processing we listen DOMMenubarActive/Inactive
612 notifyOf
= kNotifyOfFocus
;
615 // Restore focus to where it was.
616 if (notifyOf
& kNotifyOfFocus
) {
617 FocusMgr()->ActiveItemChanged(nullptr);
619 if (logging::IsEnabled(logging::eFocus
)) {
620 logging::ActiveItemChangeCausedBy("popuphiding", popup
);
625 // Fire expanded state change event.
626 if (notifyOf
& kNotifyOfState
) {
627 RefPtr
<AccEvent
> event
=
628 new AccStateChangeEvent(widget
, states::EXPANDED
, false);
629 document
->FireDelayedEvent(event
);
633 static void GetPropertyBagFromEvent(Event
* aEvent
,
634 nsIPropertyBag2
** aPropertyBag
) {
635 *aPropertyBag
= nullptr;
637 CustomEvent
* customEvent
= aEvent
->AsCustomEvent();
638 if (!customEvent
) return;
641 if (!jsapi
.Init(customEvent
->GetParentObject())) return;
643 JSContext
* cx
= jsapi
.cx();
644 JS::Rooted
<JS::Value
> detail(cx
);
645 customEvent
->GetDetail(cx
, &detail
);
646 if (!detail
.isObject()) return;
648 JS::Rooted
<JSObject
*> detailObj(cx
, &detail
.toObject());
651 nsCOMPtr
<nsIPropertyBag2
> propBag
;
652 rv
= UnwrapArg
<nsIPropertyBag2
>(cx
, detailObj
, getter_AddRefs(propBag
));
653 if (NS_FAILED(rv
)) return;
655 propBag
.forget(aPropertyBag
);
658 void RootAccessible::HandleTreeRowCountChangedEvent(
659 Event
* aEvent
, XULTreeAccessible
* aAccessible
) {
660 nsCOMPtr
<nsIPropertyBag2
> propBag
;
661 GetPropertyBagFromEvent(aEvent
, getter_AddRefs(propBag
));
662 if (!propBag
) return;
665 int32_t index
, count
;
666 rv
= propBag
->GetPropertyAsInt32(u
"index"_ns
, &index
);
667 if (NS_FAILED(rv
)) return;
669 rv
= propBag
->GetPropertyAsInt32(u
"count"_ns
, &count
);
670 if (NS_FAILED(rv
)) return;
672 aAccessible
->InvalidateCache(index
, count
);
675 void RootAccessible::HandleTreeInvalidatedEvent(
676 Event
* aEvent
, XULTreeAccessible
* aAccessible
) {
677 nsCOMPtr
<nsIPropertyBag2
> propBag
;
678 GetPropertyBagFromEvent(aEvent
, getter_AddRefs(propBag
));
679 if (!propBag
) return;
681 int32_t startRow
= 0, endRow
= -1, startCol
= 0, endCol
= -1;
682 propBag
->GetPropertyAsInt32(u
"startrow"_ns
, &startRow
);
683 propBag
->GetPropertyAsInt32(u
"endrow"_ns
, &endRow
);
684 propBag
->GetPropertyAsInt32(u
"startcolumn"_ns
, &startCol
);
685 propBag
->GetPropertyAsInt32(u
"endcolumn"_ns
, &endCol
);
687 aAccessible
->TreeViewInvalidated(startRow
, endRow
, startCol
, endCol
);
690 RemoteAccessible
* RootAccessible::GetPrimaryRemoteTopLevelContentDoc() const {
691 nsCOMPtr
<nsIDocShellTreeOwner
> owner
;
692 mDocumentNode
->GetDocShell()->GetTreeOwner(getter_AddRefs(owner
));
693 NS_ENSURE_TRUE(owner
, nullptr);
695 nsCOMPtr
<nsIRemoteTab
> remoteTab
;
696 owner
->GetPrimaryRemoteTab(getter_AddRefs(remoteTab
));
701 auto tab
= static_cast<dom::BrowserHost
*>(remoteTab
.get());
702 return tab
->GetTopLevelDocAccessible();