LCOV - code coverage report
Current view: directory - accessible/src/base - nsRootAccessible.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 303 0 0.0 %
Date: 2012-06-02 Functions: 22 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "mozilla/Util.h"
      39                 : 
      40                 : #define CreateEvent CreateEventA
      41                 : #include "nsIDOMDocument.h"
      42                 : 
      43                 : #include "nsAccessibilityService.h"
      44                 : #include "nsApplicationAccessibleWrap.h"
      45                 : #include "nsAccUtils.h"
      46                 : #include "nsCoreUtils.h"
      47                 : #include "Relation.h"
      48                 : #include "Role.h"
      49                 : #include "States.h"
      50                 : 
      51                 : #include "mozilla/dom/Element.h"
      52                 : #include "nsHTMLSelectAccessible.h"
      53                 : #include "nsIAccessibleRelation.h"
      54                 : #include "nsIDocShell.h"
      55                 : #include "nsIDocShellTreeItem.h"
      56                 : #include "nsIDocShellTreeNode.h"
      57                 : #include "nsIDocShellTreeOwner.h"
      58                 : #include "nsIDOMElement.h"
      59                 : #include "nsIDOMEventListener.h"
      60                 : #include "nsIDOMEventTarget.h"
      61                 : #include "nsIDOMHTMLAnchorElement.h"
      62                 : #include "nsIDOMHTMLImageElement.h"
      63                 : #include "nsIDOMHTMLInputElement.h"
      64                 : #include "nsIDOMHTMLSelectElement.h"
      65                 : #include "nsIDOMDataContainerEvent.h"
      66                 : #include "nsIDOMNSEvent.h"
      67                 : #include "nsIDOMXULMultSelectCntrlEl.h"
      68                 : #include "nsIDOMXULPopupElement.h"
      69                 : #include "nsIDocument.h"
      70                 : #include "nsEventListenerManager.h"
      71                 : #include "nsIFrame.h"
      72                 : #include "nsIHTMLDocument.h"
      73                 : #include "nsIInterfaceRequestorUtils.h"
      74                 : #include "nsISelectionPrivate.h"
      75                 : #include "nsIServiceManager.h"
      76                 : #include "nsPIDOMWindow.h"
      77                 : #include "nsIWebBrowserChrome.h"
      78                 : #include "nsReadableUtils.h"
      79                 : #include "nsRootAccessible.h"
      80                 : #include "nsIPrivateDOMEvent.h"
      81                 : #include "nsFocusManager.h"
      82                 : 
      83                 : #ifdef MOZ_XUL
      84                 : #include "nsXULTreeAccessible.h"
      85                 : #include "nsIXULDocument.h"
      86                 : #include "nsIXULWindow.h"
      87                 : #endif
      88                 : 
      89                 : using namespace mozilla;
      90                 : using namespace mozilla::a11y;
      91                 : 
      92                 : ////////////////////////////////////////////////////////////////////////////////
      93                 : // nsISupports
      94                 : 
      95                 : // Expanded version of NS_IMPL_ISUPPORTS_INHERITED2 
      96                 : // so we can QI directly to concrete nsRootAccessible
      97               0 : NS_IMPL_QUERY_HEAD(nsRootAccessible)
      98               0 : NS_IMPL_QUERY_BODY(nsIDOMEventListener)
      99               0 : if (aIID.Equals(NS_GET_IID(nsRootAccessible)))
     100               0 :   foundInterface = reinterpret_cast<nsISupports*>(this);
     101                 : else
     102               0 : NS_IMPL_QUERY_TAIL_INHERITING(nsDocAccessible)
     103                 : 
     104               0 : NS_IMPL_ADDREF_INHERITED(nsRootAccessible, nsDocAccessible) 
     105               0 : NS_IMPL_RELEASE_INHERITED(nsRootAccessible, nsDocAccessible)
     106                 : 
     107                 : ////////////////////////////////////////////////////////////////////////////////
     108                 : // Constructor/desctructor
     109                 : 
     110               0 : nsRootAccessible::
     111                 :   nsRootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
     112                 :                    nsIPresShell* aPresShell) :
     113               0 :   nsDocAccessibleWrap(aDocument, aRootContent, aPresShell)
     114                 : {
     115               0 :   mFlags |= eRootAccessible;
     116               0 : }
     117                 : 
     118               0 : nsRootAccessible::~nsRootAccessible()
     119                 : {
     120               0 : }
     121                 : 
     122                 : ////////////////////////////////////////////////////////////////////////////////
     123                 : // nsIAccessible
     124                 : 
     125                 : /* readonly attribute AString name; */
     126                 : NS_IMETHODIMP
     127               0 : nsRootAccessible::GetName(nsAString& aName)
     128                 : {
     129               0 :   aName.Truncate();
     130                 : 
     131               0 :   if (!mDocument) {
     132               0 :     return NS_ERROR_FAILURE;
     133                 :   }
     134                 : 
     135               0 :   if (mRoleMapEntry) {
     136               0 :     nsAccessible::GetName(aName);
     137               0 :     if (!aName.IsEmpty()) {
     138               0 :       return NS_OK;
     139                 :     }
     140                 :   }
     141                 : 
     142               0 :   nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
     143               0 :   return document->GetTitle(aName);
     144                 : }
     145                 : 
     146                 : role
     147               0 : nsRootAccessible::NativeRole()
     148                 : {
     149                 :   // If it's a <dialog> or <wizard>, use roles::DIALOG instead
     150               0 :   dom::Element *root = mDocument->GetRootElement();
     151               0 :   if (root) {
     152               0 :     nsCOMPtr<nsIDOMElement> rootElement(do_QueryInterface(root));
     153               0 :     if (rootElement) {
     154               0 :       nsAutoString name;
     155               0 :       rootElement->GetLocalName(name);
     156               0 :       if (name.EqualsLiteral("dialog") || name.EqualsLiteral("wizard")) {
     157               0 :         return roles::DIALOG; // Always at the root
     158                 :       }
     159                 :     }
     160                 :   }
     161                 : 
     162               0 :   return nsDocAccessibleWrap::NativeRole();
     163                 : }
     164                 : 
     165                 : // nsRootAccessible protected member
     166                 : #ifdef MOZ_XUL
     167               0 : PRUint32 nsRootAccessible::GetChromeFlags()
     168                 : {
     169                 :   // Return the flag set for the top level window as defined 
     170                 :   // by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
     171                 :   // Not simple: nsIXULWindow is not just a QI from nsIDOMWindow
     172                 :   nsCOMPtr<nsIDocShellTreeItem> treeItem =
     173               0 :     nsCoreUtils::GetDocShellTreeItemFor(mDocument);
     174               0 :   NS_ENSURE_TRUE(treeItem, 0);
     175               0 :   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     176               0 :   treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
     177               0 :   NS_ENSURE_TRUE(treeOwner, 0);
     178               0 :   nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
     179               0 :   if (!xulWin) {
     180               0 :     return 0;
     181                 :   }
     182                 :   PRUint32 chromeFlags;
     183               0 :   xulWin->GetChromeFlags(&chromeFlags);
     184               0 :   return chromeFlags;
     185                 : }
     186                 : #endif
     187                 : 
     188                 : PRUint64
     189               0 : nsRootAccessible::NativeState()
     190                 : {
     191               0 :   PRUint64 states = nsDocAccessibleWrap::NativeState();
     192                 : 
     193                 : #ifdef MOZ_XUL
     194               0 :   PRUint32 chromeFlags = GetChromeFlags();
     195               0 :   if (chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE)
     196               0 :     states |= states::SIZEABLE;
     197                 :     // If it has a titlebar it's movable
     198                 :     // XXX unless it's minimized or maximized, but not sure
     199                 :     //     how to detect that
     200               0 :   if (chromeFlags & nsIWebBrowserChrome::CHROME_TITLEBAR)
     201               0 :     states |= states::MOVEABLE;
     202               0 :   if (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL)
     203               0 :     states |= states::MODAL;
     204                 : #endif
     205                 : 
     206               0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
     207               0 :   if (fm) {
     208               0 :     nsCOMPtr<nsIDOMWindow> rootWindow;
     209               0 :     GetWindow(getter_AddRefs(rootWindow));
     210                 : 
     211               0 :     nsCOMPtr<nsIDOMWindow> activeWindow;
     212               0 :     fm->GetActiveWindow(getter_AddRefs(activeWindow));
     213               0 :     if (activeWindow == rootWindow)
     214               0 :       states |= states::ACTIVE;
     215                 :   }
     216                 : 
     217               0 :   return states;
     218                 : }
     219                 : 
     220                 : const char* const docEvents[] = {
     221                 : #ifdef DEBUG_DRAGDROPSTART
     222                 :   // Capture mouse over events and fire fake DRAGDROPSTART event to simplify
     223                 :   // debugging a11y objects with event viewers
     224                 :   "mouseover",
     225                 : #endif
     226                 :   // capture Form change events 
     227                 :   "select",
     228                 :   // capture ValueChange events (fired whenever value changes, immediately after, whether focus moves or not)
     229                 :   "ValueChange",
     230                 :   // capture AlertActive events (fired whenever alert pops up)
     231                 :   "AlertActive",
     232                 :   // add ourself as a TreeViewChanged listener (custom event fired in nsTreeBodyFrame.cpp)
     233                 :   "TreeViewChanged",
     234                 :   "TreeRowCountChanged",
     235                 :   "TreeInvalidated",
     236                 :   // add ourself as a OpenStateChange listener (custom event fired in tree.xml)
     237                 :   "OpenStateChange",
     238                 :   // add ourself as a CheckboxStateChange listener (custom event fired in nsHTMLInputElement.cpp)
     239                 :   "CheckboxStateChange",
     240                 :   // add ourself as a RadioStateChange Listener ( custom event fired in in nsHTMLInputElement.cpp  & radio.xml)
     241                 :   "RadioStateChange",
     242                 :   "popupshown",
     243                 :   "popuphiding",
     244                 :   "DOMMenuInactive",
     245                 :   "DOMMenuItemActive",
     246                 :   "DOMMenuItemInactive",
     247                 :   "DOMMenuBarActive",
     248                 :   "DOMMenuBarInactive"
     249                 : };
     250                 : 
     251               0 : nsresult nsRootAccessible::AddEventListeners()
     252                 : {
     253                 :   // nsIDOMEventTarget interface allows to register event listeners to
     254                 :   // receive untrusted events (synthetic events generated by untrusted code).
     255                 :   // For example, XBL bindings implementations for elements that are hosted in
     256                 :   // non chrome document fire untrusted events.
     257               0 :   nsCOMPtr<nsIDOMEventTarget> nstarget(do_QueryInterface(mDocument));
     258                 : 
     259               0 :   if (nstarget) {
     260               0 :     for (const char* const* e = docEvents,
     261               0 :                    * const* e_end = ArrayEnd(docEvents);
     262                 :          e < e_end; ++e) {
     263               0 :       nsresult rv = nstarget->AddEventListener(NS_ConvertASCIItoUTF16(*e),
     264               0 :                                                this, true, true, 2);
     265               0 :       NS_ENSURE_SUCCESS(rv, rv);
     266                 :     }
     267                 :   }
     268                 : 
     269               0 :   if (!mCaretAccessible) {
     270               0 :     mCaretAccessible = new nsCaretAccessible(this);
     271                 :   }
     272                 : 
     273               0 :   return nsDocAccessible::AddEventListeners();
     274                 : }
     275                 : 
     276               0 : nsresult nsRootAccessible::RemoveEventListeners()
     277                 : {
     278               0 :   nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mDocument));
     279               0 :   if (target) { 
     280               0 :     for (const char* const* e = docEvents,
     281               0 :                    * const* e_end = ArrayEnd(docEvents);
     282                 :          e < e_end; ++e) {
     283               0 :       nsresult rv = target->RemoveEventListener(NS_ConvertASCIItoUTF16(*e), this, true);
     284               0 :       NS_ENSURE_SUCCESS(rv, rv);
     285                 :     }
     286                 :   }
     287                 : 
     288                 :   // Do this before removing clearing caret accessible, so that it can use
     289                 :   // shutdown the caret accessible's selection listener
     290               0 :   nsDocAccessible::RemoveEventListeners();
     291                 : 
     292               0 :   if (mCaretAccessible) {
     293               0 :     mCaretAccessible->Shutdown();
     294               0 :     mCaretAccessible = nsnull;
     295                 :   }
     296                 : 
     297               0 :   return NS_OK;
     298                 : }
     299                 : 
     300                 : ////////////////////////////////////////////////////////////////////////////////
     301                 : // public
     302                 : 
     303                 : nsCaretAccessible*
     304               0 : nsRootAccessible::GetCaretAccessible()
     305                 : {
     306               0 :   return mCaretAccessible;
     307                 : }
     308                 : 
     309                 : void
     310               0 : nsRootAccessible::DocumentActivated(nsDocAccessible* aDocument)
     311                 : {
     312               0 : }
     313                 : 
     314                 : ////////////////////////////////////////////////////////////////////////////////
     315                 : // nsIDOMEventListener
     316                 : 
     317                 : NS_IMETHODIMP
     318               0 : nsRootAccessible::HandleEvent(nsIDOMEvent* aDOMEvent)
     319                 : {
     320               0 :   nsCOMPtr<nsIDOMNSEvent> DOMNSEvent(do_QueryInterface(aDOMEvent));
     321               0 :   nsCOMPtr<nsIDOMEventTarget> DOMEventTarget;
     322               0 :   DOMNSEvent->GetOriginalTarget(getter_AddRefs(DOMEventTarget));
     323               0 :   nsCOMPtr<nsINode> origTargetNode(do_QueryInterface(DOMEventTarget));
     324               0 :   if (!origTargetNode)
     325               0 :     return NS_OK;
     326                 : 
     327                 :   nsDocAccessible* document =
     328               0 :     GetAccService()->GetDocAccessible(origTargetNode->OwnerDoc());
     329                 : 
     330               0 :   if (document) {
     331                 : #ifdef DEBUG_NOTIFICATIONS
     332                 :     if (origTargetNode->IsElement()) {
     333                 :       nsIContent* elm = origTargetNode->AsElement();
     334                 : 
     335                 :       nsAutoString tag;
     336                 :       elm->Tag()->ToString(tag);
     337                 : 
     338                 :       nsIAtom* atomid = elm->GetID();
     339                 :       nsCAutoString id;
     340                 :       if (atomid)
     341                 :         atomid->ToUTF8String(id);
     342                 : 
     343                 :       nsAutoString eventType;
     344                 :       aDOMEvent->GetType(eventType);
     345                 : 
     346                 :       printf("\nPend DOM event processing for %s@id='%s', type: %s\n\n",
     347                 :              NS_ConvertUTF16toUTF8(tag).get(), id.get(),
     348                 :              NS_ConvertUTF16toUTF8(eventType).get());
     349                 :     }
     350                 : #endif
     351                 : 
     352                 :     // Root accessible exists longer than any of its descendant documents so
     353                 :     // that we are guaranteed notification is processed before root accessible
     354                 :     // is destroyed.
     355                 :     document->HandleNotification<nsRootAccessible, nsIDOMEvent>
     356               0 :       (this, &nsRootAccessible::ProcessDOMEvent, aDOMEvent);
     357                 :   }
     358                 : 
     359               0 :   return NS_OK;
     360                 : }
     361                 : 
     362                 : // nsRootAccessible protected
     363                 : void
     364               0 : nsRootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
     365                 : {
     366               0 :   nsCOMPtr<nsIDOMNSEvent> DOMNSEvent(do_QueryInterface(aDOMEvent));
     367               0 :   nsCOMPtr<nsIDOMEventTarget> DOMEventTarget;
     368               0 :   DOMNSEvent->GetOriginalTarget(getter_AddRefs(DOMEventTarget));
     369               0 :   nsCOMPtr<nsINode> origTargetNode(do_QueryInterface(DOMEventTarget));
     370                 : 
     371               0 :   nsAutoString eventType;
     372               0 :   aDOMEvent->GetType(eventType);
     373                 : 
     374               0 :   if (eventType.EqualsLiteral("popuphiding")) {
     375               0 :     HandlePopupHidingEvent(origTargetNode);
     376                 :     return;
     377                 :   }
     378                 : 
     379               0 :   nsDocAccessible* targetDocument = GetAccService()->
     380               0 :     GetDocAccessible(origTargetNode->OwnerDoc());
     381               0 :   NS_ASSERTION(targetDocument, "No document while accessible is in document?!");
     382                 : 
     383                 :   nsAccessible* accessible = 
     384               0 :     targetDocument->GetAccessibleOrContainer(origTargetNode);
     385               0 :   if (!accessible)
     386                 :     return;
     387                 : 
     388               0 :   nsINode* targetNode = accessible->GetNode();
     389                 : 
     390                 : #ifdef MOZ_XUL
     391               0 :   nsRefPtr<nsXULTreeAccessible> treeAcc;
     392               0 :   if (targetNode->IsElement() &&
     393               0 :       targetNode->AsElement()->NodeInfo()->Equals(nsGkAtoms::tree,
     394               0 :                                                   kNameSpaceID_XUL)) {
     395               0 :     treeAcc = do_QueryObject(accessible);
     396               0 :     if (treeAcc) {
     397               0 :       if (eventType.EqualsLiteral("TreeViewChanged")) {
     398               0 :         treeAcc->TreeViewChanged();
     399                 :         return;
     400                 :       }
     401                 : 
     402               0 :       if (eventType.EqualsLiteral("TreeRowCountChanged")) {
     403               0 :         HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
     404                 :         return;
     405                 :       }
     406                 : 
     407               0 :       if (eventType.EqualsLiteral("TreeInvalidated")) {
     408               0 :         HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
     409                 :         return;
     410                 :       }
     411                 :     }
     412                 :   }
     413                 : #endif
     414                 : 
     415               0 :   if (eventType.EqualsLiteral("RadioStateChange")) {
     416               0 :     PRUint64 state = accessible->State();
     417                 : 
     418                 :     // radiogroup in prefWindow is exposed as a list,
     419                 :     // and panebutton is exposed as XULListitem in A11y.
     420                 :     // nsXULListitemAccessible::GetStateInternal uses STATE_SELECTED in this case,
     421                 :     // so we need to check states::SELECTED also.
     422               0 :     bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0;
     423                 : 
     424                 :     nsRefPtr<AccEvent> accEvent =
     425               0 :       new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
     426               0 :     nsEventShell::FireEvent(accEvent);
     427                 : 
     428               0 :     if (isEnabled) {
     429               0 :       FocusMgr()->ActiveItemChanged(accessible);
     430                 :       A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("RadioStateChange", accessible)
     431                 :     }
     432                 : 
     433                 :     return;
     434                 :   }
     435                 : 
     436               0 :   if (eventType.EqualsLiteral("CheckboxStateChange")) {
     437               0 :     PRUint64 state = accessible->State();
     438                 : 
     439               0 :     bool isEnabled = !!(state & states::CHECKED);
     440                 : 
     441                 :     nsRefPtr<AccEvent> accEvent =
     442               0 :       new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
     443                 : 
     444               0 :     nsEventShell::FireEvent(accEvent);
     445                 :     return;
     446                 :   }
     447                 : 
     448               0 :   nsAccessible* treeItemAcc = nsnull;
     449                 : #ifdef MOZ_XUL
     450                 :   // If it's a tree element, need the currently selected item.
     451               0 :   if (treeAcc) {
     452               0 :     treeItemAcc = accessible->CurrentItem();
     453               0 :     if (treeItemAcc)
     454               0 :       accessible = treeItemAcc;
     455                 :   }
     456                 : 
     457               0 :   if (treeItemAcc && eventType.EqualsLiteral("OpenStateChange")) {
     458               0 :     PRUint64 state = accessible->State();
     459               0 :     bool isEnabled = (state & states::EXPANDED) != 0;
     460                 : 
     461                 :     nsRefPtr<AccEvent> accEvent =
     462               0 :       new AccStateChangeEvent(accessible, states::EXPANDED, isEnabled);
     463               0 :     nsEventShell::FireEvent(accEvent);
     464                 :     return;
     465                 :   }
     466                 : 
     467               0 :   if (treeItemAcc && eventType.EqualsLiteral("select")) {
     468                 :     // XXX: We shouldn't be based on DOM select event which doesn't provide us
     469                 :     // any context info. We should integrate into nsTreeSelection instead.
     470                 :     // If multiselect tree, we should fire selectionadd or selection removed
     471               0 :     if (FocusMgr()->HasDOMFocus(targetNode)) {
     472                 :       nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel =
     473               0 :         do_QueryInterface(targetNode);
     474               0 :       nsAutoString selType;
     475               0 :       multiSel->GetSelType(selType);
     476               0 :       if (selType.IsEmpty() || !selType.EqualsLiteral("single")) {
     477                 :         // XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
     478                 :         // for each tree item. Perhaps each tree item will need to cache its
     479                 :         // selection state and fire an event after a DOM "select" event when
     480                 :         // that state changes. nsXULTreeAccessible::UpdateTreeSelection();
     481                 :         nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
     482               0 :                                 accessible);
     483                 :         return;
     484                 :       }
     485                 : 
     486                 :       nsRefPtr<AccSelChangeEvent> selChangeEvent =
     487                 :         new AccSelChangeEvent(treeAcc, treeItemAcc,
     488               0 :                               AccSelChangeEvent::eSelectionAdd);
     489               0 :       nsEventShell::FireEvent(selChangeEvent);
     490                 :       return;
     491                 :     }
     492                 :   }
     493                 :   else
     494                 : #endif
     495               0 :   if (eventType.EqualsLiteral("AlertActive")) {
     496               0 :     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible);
     497                 :   }
     498               0 :   else if (eventType.EqualsLiteral("popupshown")) {
     499               0 :     HandlePopupShownEvent(accessible);
     500                 :   }
     501               0 :   else if (eventType.EqualsLiteral("DOMMenuInactive")) {
     502               0 :     if (accessible->Role() == roles::MENUPOPUP) {
     503                 :       nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
     504               0 :                               accessible);
     505                 :     }
     506                 :   }
     507               0 :   else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
     508               0 :     FocusMgr()->ActiveItemChanged(accessible);
     509                 :     A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuItemActive", accessible)
     510                 :   }
     511               0 :   else if (eventType.EqualsLiteral("DOMMenuItemInactive")) {
     512                 :     // Process DOMMenuItemInactive event for autocomplete only because this is
     513                 :     // unique widget that may acquire focus from autocomplete popup while popup
     514                 :     // stays open and has no active item. In case of XUL tree autocomplete
     515                 :     // popup this event is fired for tree accessible.
     516                 :     nsAccessible* widget =
     517               0 :       accessible->IsWidget() ? accessible : accessible->ContainerWidget();
     518               0 :     if (widget && widget->IsAutoCompletePopup()) {
     519               0 :       FocusMgr()->ActiveItemChanged(nsnull);
     520                 :       A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuItemInactive", accessible)
     521                 :     }
     522                 :   }
     523               0 :   else if (eventType.EqualsLiteral("DOMMenuBarActive")) {  // Always from user input
     524                 :     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START,
     525               0 :                             accessible, eFromUserInput);
     526                 : 
     527                 :     // Notify of active item change when menubar gets active and if it has
     528                 :     // current item. This is a case of mouseover (set current menuitem) and
     529                 :     // mouse click (activate the menubar). If menubar doesn't have current item
     530                 :     // (can be a case of menubar activation from keyboard) then ignore this
     531                 :     // notification because later we'll receive DOMMenuItemActive event after
     532                 :     // current menuitem is set.
     533               0 :     nsAccessible* activeItem = accessible->CurrentItem();
     534               0 :     if (activeItem) {
     535               0 :       FocusMgr()->ActiveItemChanged(activeItem);
     536                 :       A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuBarActive", accessible)
     537                 :     }
     538                 :   }
     539               0 :   else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {  // Always from user input
     540                 :     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END,
     541               0 :                             accessible, eFromUserInput);
     542                 : 
     543               0 :     FocusMgr()->ActiveItemChanged(nsnull);
     544                 :     A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuBarInactive", accessible)
     545                 :   }
     546               0 :   else if (eventType.EqualsLiteral("ValueChange")) {
     547                 :     targetDocument->
     548                 :       FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
     549               0 :                                  targetNode, AccEvent::eRemoveDupes);
     550                 :   }
     551                 : #ifdef DEBUG_DRAGDROPSTART
     552                 :   else if (eventType.EqualsLiteral("mouseover")) {
     553                 :     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
     554                 :                             accessible);
     555                 :   }
     556                 : #endif
     557                 : }
     558                 : 
     559                 : 
     560                 : ////////////////////////////////////////////////////////////////////////////////
     561                 : // nsAccessNode
     562                 : 
     563                 : void
     564               0 : nsRootAccessible::Shutdown()
     565                 : {
     566                 :   // Called manually or by nsAccessNode::LastRelease()
     567               0 :   if (!PresShell())
     568               0 :     return;  // Already shutdown
     569                 : 
     570               0 :   nsDocAccessibleWrap::Shutdown();
     571                 : }
     572                 : 
     573                 : // nsIAccessible method
     574                 : Relation
     575               0 : nsRootAccessible::RelationByType(PRUint32 aType)
     576                 : {
     577               0 :   if (!mDocument || aType != nsIAccessibleRelation::RELATION_EMBEDS)
     578               0 :     return nsDocAccessibleWrap::RelationByType(aType);
     579                 : 
     580               0 :   nsIDOMWindow* rootWindow = mDocument->GetWindow();
     581               0 :   if (rootWindow) {
     582               0 :     nsCOMPtr<nsIDOMWindow> contentWindow;
     583               0 :     rootWindow->GetContent(getter_AddRefs(contentWindow));
     584               0 :     if (contentWindow) {
     585               0 :       nsCOMPtr<nsIDOMDocument> contentDOMDocument;
     586               0 :       contentWindow->GetDocument(getter_AddRefs(contentDOMDocument));
     587                 :       nsCOMPtr<nsIDocument> contentDocumentNode =
     588               0 :         do_QueryInterface(contentDOMDocument);
     589               0 :       if (contentDocumentNode) {
     590                 :         nsDocAccessible* contentDocument =
     591               0 :           GetAccService()->GetDocAccessible(contentDocumentNode);
     592               0 :         if (contentDocument)
     593               0 :           return Relation(contentDocument);
     594                 :       }
     595                 :     }
     596                 :   }
     597                 : 
     598               0 :   return Relation();
     599                 : }
     600                 : 
     601                 : ////////////////////////////////////////////////////////////////////////////////
     602                 : // Protected members
     603                 : 
     604                 : void
     605               0 : nsRootAccessible::HandlePopupShownEvent(nsAccessible* aAccessible)
     606                 : {
     607               0 :   roles::Role role = aAccessible->Role();
     608                 : 
     609               0 :   if (role == roles::MENUPOPUP) {
     610                 :     // Don't fire menupopup events for combobox and autocomplete lists.
     611                 :     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
     612               0 :                             aAccessible);
     613               0 :     return;
     614                 :   }
     615                 : 
     616               0 :   if (role == roles::TOOLTIP) {
     617                 :     // There is a single <xul:tooltip> node which Mozilla moves around.
     618                 :     // The accessible for it stays the same no matter where it moves. 
     619                 :     // AT's expect to get an EVENT_SHOW for the tooltip. 
     620                 :     // In event callback the tooltip's accessible will be ready.
     621               0 :     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SHOW, aAccessible);
     622               0 :     return;
     623                 :   }
     624                 : 
     625               0 :   if (role == roles::COMBOBOX_LIST) {
     626                 :     // Fire expanded state change event for comboboxes and autocompeletes.
     627               0 :     nsAccessible* combobox = aAccessible->Parent();
     628               0 :     if (!combobox)
     629               0 :       return;
     630                 : 
     631               0 :     roles::Role comboboxRole = combobox->Role();
     632               0 :     if (comboboxRole == roles::COMBOBOX || 
     633                 :         comboboxRole == roles::AUTOCOMPLETE) {
     634                 :       nsRefPtr<AccEvent> event =
     635               0 :         new AccStateChangeEvent(combobox, states::EXPANDED, true);
     636               0 :       if (event)
     637               0 :         nsEventShell::FireEvent(event);
     638                 :     }
     639                 :   }
     640                 : }
     641                 : 
     642                 : void
     643               0 : nsRootAccessible::HandlePopupHidingEvent(nsINode* aPopupNode)
     644                 : {
     645                 :   // Get popup accessible. There are cases when popup element isn't accessible
     646                 :   // but an underlying widget is and behaves like popup, an example is
     647                 :   // autocomplete popups.
     648               0 :   nsDocAccessible* document = nsAccUtils::GetDocAccessibleFor(aPopupNode);
     649               0 :   if (!document)
     650               0 :     return;
     651                 : 
     652               0 :   nsAccessible* popup = document->GetAccessible(aPopupNode);
     653               0 :   if (!popup) {
     654               0 :     nsAccessible* popupContainer = document->GetContainerAccessible(aPopupNode);
     655               0 :     if (!popupContainer)
     656               0 :       return;
     657                 : 
     658               0 :     PRInt32 childCount = popupContainer->GetChildCount();
     659               0 :     for (PRInt32 idx = 0; idx < childCount; idx++) {
     660               0 :       nsAccessible* child = popupContainer->GetChildAt(idx);
     661               0 :       if (child->IsAutoCompletePopup()) {
     662               0 :         popup = child;
     663               0 :         break;
     664                 :       }
     665                 :     }
     666                 : 
     667                 :     // No popup no events. Focus is managed by DOM. This is a case for
     668                 :     // menupopups of menus on Linux since there are no accessible for popups.
     669               0 :     if (!popup)
     670               0 :       return;
     671                 :   }
     672                 : 
     673                 :   // In case of autocompletes and comboboxes fire state change event for
     674                 :   // expanded state. Note, HTML form autocomplete isn't a subject of state
     675                 :   // change event because they aren't autocompletes strictly speaking.
     676                 :   // When popup closes (except nested popups and menus) then fire focus event to
     677                 :   // where it was. The focus event is expected even if popup didn't take a focus.
     678                 : 
     679                 :   static const PRUint32 kNotifyOfFocus = 1;
     680                 :   static const PRUint32 kNotifyOfState = 2;
     681               0 :   PRUint32 notifyOf = 0;
     682                 : 
     683                 :   // HTML select is target of popuphidding event. Otherwise get container
     684                 :   // widget. No container widget means this is either tooltip or menupopup.
     685                 :   // No events in the former case.
     686               0 :   nsAccessible* widget = nsnull;
     687               0 :   if (popup->IsCombobox()) {
     688               0 :     widget = popup;
     689                 :   } else {
     690               0 :     widget = popup->ContainerWidget();
     691               0 :     if (!widget) {
     692               0 :       if (!popup->IsMenuPopup())
     693               0 :         return;
     694                 : 
     695               0 :       widget = popup;
     696                 :     }
     697                 :   }
     698                 : 
     699               0 :   if (popup->IsAutoCompletePopup()) {
     700                 :     // No focus event for autocomplete because it's managed by
     701                 :     // DOMMenuItemInactive events.
     702               0 :     if (widget->IsAutoComplete())
     703               0 :       notifyOf = kNotifyOfState;
     704                 : 
     705               0 :   } else if (widget->IsCombobox()) {
     706                 :     // Fire focus for active combobox, otherwise the focus is managed by DOM
     707                 :     // focus notifications. Always fire state change event.
     708               0 :     if (widget->IsActiveWidget())
     709               0 :       notifyOf = kNotifyOfFocus;
     710               0 :     notifyOf |= kNotifyOfState;
     711                 : 
     712               0 :   } else if (widget->IsMenuButton()) {
     713                 :     // Can be a part of autocomplete.
     714               0 :     nsAccessible* compositeWidget = widget->ContainerWidget();
     715               0 :     if (compositeWidget && compositeWidget->IsAutoComplete()) {
     716               0 :       widget = compositeWidget;
     717               0 :       notifyOf = kNotifyOfState;
     718                 :     }
     719                 : 
     720                 :     // Autocomplete (like searchbar) can be inactive when popup hiddens
     721               0 :     notifyOf |= kNotifyOfFocus;
     722                 : 
     723               0 :   } else if (widget == popup) {
     724                 :     // Top level context menus and alerts.
     725                 :     // Ignore submenus and menubar. When submenu is closed then sumbenu
     726                 :     // container menuitem takes a focus via DOMMenuItemActive notification.
     727                 :     // For menubars processing we listen DOMMenubarActive/Inactive
     728                 :     // notifications.
     729               0 :     notifyOf = kNotifyOfFocus;
     730                 :   }
     731                 : 
     732                 :   // Restore focus to where it was.
     733               0 :   if (notifyOf & kNotifyOfFocus) {
     734               0 :     FocusMgr()->ActiveItemChanged(nsnull);
     735                 :     A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("popuphiding", popup)
     736                 :   }
     737                 : 
     738                 :   // Fire expanded state change event.
     739               0 :   if (notifyOf & kNotifyOfState) {
     740                 :     nsRefPtr<AccEvent> event =
     741               0 :       new AccStateChangeEvent(widget, states::EXPANDED, false);
     742               0 :     document->FireDelayedAccessibleEvent(event);
     743                 :   }
     744                 : }
     745                 : 
     746                 : #ifdef MOZ_XUL
     747                 : void
     748               0 : nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent* aEvent,
     749                 :                                                  nsXULTreeAccessible* aAccessible)
     750                 : {
     751               0 :   nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
     752               0 :   if (!dataEvent)
     753                 :     return;
     754                 : 
     755               0 :   nsCOMPtr<nsIVariant> indexVariant;
     756               0 :   dataEvent->GetData(NS_LITERAL_STRING("index"),
     757               0 :                      getter_AddRefs(indexVariant));
     758               0 :   if (!indexVariant)
     759                 :     return;
     760                 : 
     761               0 :   nsCOMPtr<nsIVariant> countVariant;
     762               0 :   dataEvent->GetData(NS_LITERAL_STRING("count"),
     763               0 :                      getter_AddRefs(countVariant));
     764               0 :   if (!countVariant)
     765                 :     return;
     766                 : 
     767                 :   PRInt32 index, count;
     768               0 :   indexVariant->GetAsInt32(&index);
     769               0 :   countVariant->GetAsInt32(&count);
     770                 : 
     771               0 :   aAccessible->InvalidateCache(index, count);
     772                 : }
     773                 : 
     774                 : void
     775               0 : nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
     776                 :                                              nsXULTreeAccessible* aAccessible)
     777                 : {
     778               0 :   nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
     779               0 :   if (!dataEvent)
     780                 :     return;
     781                 : 
     782               0 :   PRInt32 startRow = 0, endRow = -1, startCol = 0, endCol = -1;
     783                 : 
     784               0 :   nsCOMPtr<nsIVariant> startRowVariant;
     785               0 :   dataEvent->GetData(NS_LITERAL_STRING("startrow"),
     786               0 :                      getter_AddRefs(startRowVariant));
     787               0 :   if (startRowVariant)
     788               0 :     startRowVariant->GetAsInt32(&startRow);
     789                 : 
     790               0 :   nsCOMPtr<nsIVariant> endRowVariant;
     791               0 :   dataEvent->GetData(NS_LITERAL_STRING("endrow"),
     792               0 :                      getter_AddRefs(endRowVariant));
     793               0 :   if (endRowVariant)
     794               0 :     endRowVariant->GetAsInt32(&endRow);
     795                 : 
     796               0 :   nsCOMPtr<nsIVariant> startColVariant;
     797               0 :   dataEvent->GetData(NS_LITERAL_STRING("startcolumn"),
     798               0 :                      getter_AddRefs(startColVariant));
     799               0 :   if (startColVariant)
     800               0 :     startColVariant->GetAsInt32(&startCol);
     801                 : 
     802               0 :   nsCOMPtr<nsIVariant> endColVariant;
     803               0 :   dataEvent->GetData(NS_LITERAL_STRING("endcolumn"),
     804               0 :                      getter_AddRefs(endColVariant));
     805               0 :   if (endColVariant)
     806               0 :     endColVariant->GetAsInt32(&endCol);
     807                 : 
     808               0 :   aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
     809                 : }
     810                 : #endif

Generated by: LCOV version 1.7