LCOV - code coverage report
Current view: top level - accessible/generic - RootAccessible.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 317 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13