"Fossies" - the Fresh Open Source Software Archive

Member "UXP-2019.06.08/accessible/generic/RootAccessible.cpp" (8 Jun 2019, 23165 Bytes) of package /linux/www/UXP-2019.06.08.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "RootAccessible.cpp": 2019.03.27_vs_2019.06.08.

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