accessible/src/generic/RootAccessible.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial