2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsAccessibilityService.h"
|
2009-08-21 05:33:31 -07:00
|
|
|
#include "nsApplicationAccessibleWrap.h"
|
2010-04-26 23:52:03 -07:00
|
|
|
#include "nsAccUtils.h"
|
|
|
|
#include "nsCoreUtils.h"
|
|
|
|
#include "nsRelUtils.h"
|
2009-08-21 05:33:31 -07:00
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
#include "mozilla/dom/Element.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsHTMLSelectAccessible.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIDocShellTreeItem.h"
|
|
|
|
#include "nsIDocShellTreeNode.h"
|
|
|
|
#include "nsIDocShellTreeOwner.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMEventListener.h"
|
|
|
|
#include "nsIDOMEventTarget.h"
|
|
|
|
#include "nsIDOMHTMLAnchorElement.h"
|
|
|
|
#include "nsIDOMHTMLImageElement.h"
|
|
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
|
|
#include "nsIDOMHTMLSelectElement.h"
|
2007-12-11 00:18:04 -08:00
|
|
|
#include "nsIDOMDataContainerEvent.h"
|
2009-08-21 06:20:18 -07:00
|
|
|
#include "nsIDOMNSDocument.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMNSEvent.h"
|
|
|
|
#include "nsIDOMXULMenuListElement.h"
|
|
|
|
#include "nsIDOMXULMultSelectCntrlEl.h"
|
|
|
|
#include "nsIDOMXULSelectCntrlItemEl.h"
|
|
|
|
#include "nsIDOMXULPopupElement.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIEventListenerManager.h"
|
|
|
|
#include "nsIFrame.h"
|
2007-07-04 08:49:38 -07:00
|
|
|
#include "nsIMenuFrame.h"
|
2007-04-07 11:48:29 -07:00
|
|
|
#include "nsIHTMLDocument.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIInterfaceRequestorUtils.h"
|
|
|
|
#include "nsISelectionPrivate.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsIWebBrowserChrome.h"
|
|
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "nsRootAccessible.h"
|
|
|
|
#include "nsIDOMNSEventTarget.h"
|
|
|
|
#include "nsIDOMDocumentEvent.h"
|
2010-06-23 02:28:09 -07:00
|
|
|
#include "nsIPrivateDOMEvent.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
#include "nsFocusManager.h"
|
2010-05-05 11:18:05 -07:00
|
|
|
#include "mozilla/dom/Element.h"
|
2010-04-30 06:12:05 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
#include "nsXULTreeAccessible.h"
|
|
|
|
#include "nsIXULDocument.h"
|
|
|
|
#include "nsIXULWindow.h"
|
|
|
|
#endif
|
|
|
|
|
2010-05-05 11:18:05 -07:00
|
|
|
using namespace mozilla;
|
2010-04-30 06:12:05 -07:00
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsISupports
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Expanded version of NS_IMPL_ISUPPORTS_INHERITED2
|
|
|
|
// so we can QI directly to concrete nsRootAccessible
|
|
|
|
NS_IMPL_QUERY_HEAD(nsRootAccessible)
|
|
|
|
NS_IMPL_QUERY_BODY(nsIDOMEventListener)
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsRootAccessible)))
|
2007-07-08 00:08:04 -07:00
|
|
|
foundInterface = reinterpret_cast<nsISupports*>(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
else
|
|
|
|
NS_IMPL_QUERY_TAIL_INHERITING(nsDocAccessible)
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsRootAccessible, nsDocAccessible)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsRootAccessible, nsDocAccessible)
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructor/desctructor
|
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
nsRootAccessible::
|
|
|
|
nsRootAccessible(nsIDocument *aDocument, nsIContent *aRootContent,
|
|
|
|
nsIWeakReference *aShell) :
|
|
|
|
nsDocAccessibleWrap(aDocument, aRootContent, aShell)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRootAccessible::~nsRootAccessible()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIAccessible
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* readonly attribute AString name; */
|
2008-08-24 09:45:56 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsRootAccessible::GetName(nsAString& aName)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-08-24 09:45:56 -07:00
|
|
|
aName.Truncate();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!mDocument) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mRoleMapEntry) {
|
|
|
|
nsAccessible::GetName(aName);
|
|
|
|
if (!aName.IsEmpty()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-21 06:20:18 -07:00
|
|
|
nsCOMPtr<nsIDOMNSDocument> document(do_QueryInterface(mDocument));
|
|
|
|
return document->GetTitle(aName);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-09-04 19:14:01 -07:00
|
|
|
PRUint32
|
|
|
|
nsRootAccessible::NativeRole()
|
|
|
|
{
|
2007-03-22 10:30:00 -07:00
|
|
|
// If it's a <dialog> or <wizard>, use nsIAccessibleRole::ROLE_DIALOG instead
|
2010-05-05 11:18:05 -07:00
|
|
|
dom::Element *root = mDocument->GetRootElement();
|
2010-04-30 06:12:05 -07:00
|
|
|
if (root) {
|
|
|
|
nsCOMPtr<nsIDOMElement> rootElement(do_QueryInterface(root));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (rootElement) {
|
|
|
|
nsAutoString name;
|
|
|
|
rootElement->GetLocalName(name);
|
|
|
|
if (name.EqualsLiteral("dialog") || name.EqualsLiteral("wizard")) {
|
2010-09-04 19:14:01 -07:00
|
|
|
return nsIAccessibleRole::ROLE_DIALOG; // Always at the root
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-04 19:14:01 -07:00
|
|
|
return nsDocAccessibleWrap::NativeRole();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
// nsRootAccessible protected member
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
PRUint32 nsRootAccessible::GetChromeFlags()
|
|
|
|
{
|
|
|
|
// Return the flag set for the top level window as defined
|
|
|
|
// by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
|
|
|
|
// Not simple: nsIXULWindow is not just a QI from nsIDOMWindow
|
2007-09-05 00:39:09 -07:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem =
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCoreUtils::GetDocShellTreeItemFor(mDocument);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_TRUE(treeItem, 0);
|
|
|
|
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
|
|
|
treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
|
|
|
|
NS_ENSURE_TRUE(treeOwner, 0);
|
|
|
|
nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
|
|
|
|
if (!xulWin) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
PRUint32 chromeFlags;
|
|
|
|
xulWin->GetChromeFlags(&chromeFlags);
|
|
|
|
return chromeFlags;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-11-03 19:37:46 -08:00
|
|
|
nsresult
|
|
|
|
nsRootAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-11-03 19:37:46 -08:00
|
|
|
nsresult rv = nsDocAccessibleWrap::GetStateInternal(aState, aExtraState);
|
2008-11-26 20:04:05 -08:00
|
|
|
NS_ENSURE_A11Y_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
PRUint32 chromeFlags = GetChromeFlags();
|
|
|
|
if (chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
|
|
|
|
*aState |= nsIAccessibleStates::STATE_SIZEABLE;
|
|
|
|
}
|
|
|
|
if (chromeFlags & nsIWebBrowserChrome::CHROME_TITLEBAR) {
|
|
|
|
// If it has a titlebar it's movable
|
|
|
|
// XXX unless it's minimized or maximized, but not sure
|
|
|
|
// how to detect that
|
|
|
|
*aState |= nsIAccessibleStates::STATE_MOVEABLE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-04-02 08:56:24 -07:00
|
|
|
if (!aExtraState)
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-05-20 01:00:37 -07:00
|
|
|
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
|
|
|
if (fm) {
|
|
|
|
nsCOMPtr<nsIDOMWindow> rootWindow;
|
|
|
|
GetWindow(getter_AddRefs(rootWindow));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMWindow> activeWindow;
|
|
|
|
fm->GetActiveWindow(getter_AddRefs(activeWindow));
|
|
|
|
if (activeWindow == rootWindow)
|
|
|
|
*aExtraState |= nsIAccessibleStates::EXT_STATE_ACTIVE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2010-05-20 01:00:37 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
if (GetChromeFlags() & nsIWebBrowserChrome::CHROME_MODAL) {
|
2007-04-02 08:56:24 -07:00
|
|
|
*aExtraState |= nsIAccessibleStates::EXT_STATE_MODAL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* const docEvents[] = {
|
2007-12-10 19:30:02 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
// Capture mouse over events and fire fake DRAGDROPSTART event to simplify
|
|
|
|
// debugging a11y objects with event viewers
|
|
|
|
"mouseover",
|
|
|
|
#endif
|
2010-03-12 20:24:51 -08:00
|
|
|
// capture DOM focus and DOM blur events
|
2007-03-22 10:30:00 -07:00
|
|
|
"focus",
|
2010-03-12 20:24:51 -08:00
|
|
|
"blur",
|
2007-03-22 10:30:00 -07:00
|
|
|
// capture Form change events
|
|
|
|
"select",
|
|
|
|
// capture ValueChange events (fired whenever value changes, immediately after, whether focus moves or not)
|
|
|
|
"ValueChange",
|
|
|
|
// capture AlertActive events (fired whenever alert pops up)
|
|
|
|
"AlertActive",
|
|
|
|
// add ourself as a TreeViewChanged listener (custom event fired in nsTreeBodyFrame.cpp)
|
|
|
|
"TreeViewChanged",
|
2007-12-11 00:18:04 -08:00
|
|
|
"TreeRowCountChanged",
|
2008-02-08 04:55:57 -08:00
|
|
|
"TreeInvalidated",
|
2007-03-22 10:30:00 -07:00
|
|
|
// add ourself as a OpenStateChange listener (custom event fired in tree.xml)
|
|
|
|
"OpenStateChange",
|
|
|
|
// add ourself as a CheckboxStateChange listener (custom event fired in nsHTMLInputElement.cpp)
|
|
|
|
"CheckboxStateChange",
|
|
|
|
// add ourself as a RadioStateChange Listener ( custom event fired in in nsHTMLInputElement.cpp & radio.xml)
|
|
|
|
"RadioStateChange",
|
|
|
|
"popupshown",
|
|
|
|
"popuphiding",
|
|
|
|
"DOMMenuInactive",
|
|
|
|
"DOMMenuItemActive",
|
|
|
|
"DOMMenuBarActive",
|
2010-06-08 09:39:58 -07:00
|
|
|
"DOMMenuBarInactive"
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
nsresult nsRootAccessible::AddEventListeners()
|
|
|
|
{
|
|
|
|
// nsIDOMNSEventTarget interface allows to register event listeners to
|
|
|
|
// receive untrusted events (synthetic events generated by untrusted code).
|
|
|
|
// For example, XBL bindings implementations for elements that are hosted in
|
|
|
|
// non chrome document fire untrusted events.
|
|
|
|
nsCOMPtr<nsIDOMNSEventTarget> nstarget(do_QueryInterface(mDocument));
|
|
|
|
|
|
|
|
if (nstarget) {
|
|
|
|
for (const char* const* e = docEvents,
|
|
|
|
* const* e_end = docEvents + NS_ARRAY_LENGTH(docEvents);
|
|
|
|
e < e_end; ++e) {
|
|
|
|
nsresult rv = nstarget->AddEventListener(NS_ConvertASCIItoUTF16(*e),
|
2010-01-13 05:50:01 -08:00
|
|
|
this, PR_TRUE, PR_TRUE, 1);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mCaretAccessible) {
|
2007-06-14 10:12:50 -07:00
|
|
|
mCaretAccessible = new nsCaretAccessible(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsDocAccessible::AddEventListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult nsRootAccessible::RemoveEventListeners()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mDocument));
|
|
|
|
if (target) {
|
|
|
|
for (const char* const* e = docEvents,
|
|
|
|
* const* e_end = docEvents + NS_ARRAY_LENGTH(docEvents);
|
|
|
|
e < e_end; ++e) {
|
|
|
|
nsresult rv = target->RemoveEventListener(NS_ConvertASCIItoUTF16(*e), this, PR_TRUE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-27 10:08:50 -08:00
|
|
|
// Do this before removing clearing caret accessible, so that it can use
|
|
|
|
// shutdown the caret accessible's selection listener
|
|
|
|
nsDocAccessible::RemoveEventListeners();
|
|
|
|
|
2007-06-14 10:12:50 -07:00
|
|
|
if (mCaretAccessible) {
|
|
|
|
mCaretAccessible->Shutdown();
|
2007-03-22 10:30:00 -07:00
|
|
|
mCaretAccessible = nsnull;
|
|
|
|
}
|
|
|
|
|
2007-11-27 10:08:50 -08:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-06-14 12:19:19 -07:00
|
|
|
nsCaretAccessible*
|
2007-06-14 10:12:50 -07:00
|
|
|
nsRootAccessible::GetCaretAccessible()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-06-14 12:19:19 -07:00
|
|
|
return mCaretAccessible;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-11-08 10:36:02 -08:00
|
|
|
PRBool
|
2010-06-11 01:23:18 -07:00
|
|
|
nsRootAccessible::FireAccessibleFocusEvent(nsAccessible *aAccessible,
|
|
|
|
nsINode *aNode,
|
2009-11-08 10:36:02 -08:00
|
|
|
nsIDOMEvent *aFocusEvent,
|
|
|
|
PRBool aForceEvent,
|
2010-01-20 03:16:32 -08:00
|
|
|
PRBool aIsAsynch,
|
|
|
|
EIsFromUserInput aIsFromUserInput)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-06-15 07:53:36 -07:00
|
|
|
// Implementors: only fire delayed/async events from this method.
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mCaretAccessible) {
|
|
|
|
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aFocusEvent));
|
|
|
|
if (nsevent) {
|
|
|
|
// Use the originally focused node where the selection lives.
|
|
|
|
// For example, use the anonymous HTML:input instead of the containing
|
|
|
|
// XUL:textbox. In this case, sometimes it is a later focus event
|
|
|
|
// which points to the actual anonymous child with focus, so to be safe
|
|
|
|
// we need to reset the selection listener every time.
|
|
|
|
// This happens because when some bindings handle focus, they retarget
|
|
|
|
// focus to the appropriate child inside of themselves, but DOM focus
|
|
|
|
// stays outside on that binding parent.
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
|
|
|
|
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCOMPtr<nsIContent> realFocusedNode(do_QueryInterface(domEventTarget));
|
2007-09-18 15:44:41 -07:00
|
|
|
if (!realFocusedNode) {
|
|
|
|
// When FireCurrentFocusEvent() synthesizes a focus event,
|
|
|
|
// the orignal target does not exist, so use the passed-in node
|
|
|
|
// which is the relevant focused node
|
2010-06-11 01:23:18 -07:00
|
|
|
realFocusedNode = do_QueryInterface(aNode);
|
2007-09-18 15:44:41 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
if (realFocusedNode) {
|
2007-05-07 11:55:17 -07:00
|
|
|
mCaretAccessible->SetControlSelectionListener(realFocusedNode);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-11 18:10:26 -08:00
|
|
|
// Check for aria-activedescendant, which changes which element has focus
|
2010-06-11 01:23:18 -07:00
|
|
|
nsINode *finalFocusNode = aNode;
|
|
|
|
nsAccessible *finalFocusAccessible = aAccessible;
|
2008-10-17 03:10:43 -07:00
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
nsIContent *finalFocusContent = nsCoreUtils::GetRoleContent(finalFocusNode);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (finalFocusContent) {
|
|
|
|
nsAutoString id;
|
2007-12-11 18:10:26 -08:00
|
|
|
if (finalFocusContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant, id)) {
|
2010-06-11 01:23:18 -07:00
|
|
|
nsIDocument *doc = aNode->GetOwnerDoc();
|
|
|
|
finalFocusNode = doc->GetElementById(id);
|
2007-04-27 08:17:07 -07:00
|
|
|
if (!finalFocusNode) {
|
2010-06-15 07:53:36 -07:00
|
|
|
// If aria-activedescendant is set to nonexistant ID, then treat as focus
|
2008-03-19 18:10:36 -07:00
|
|
|
// on the activedescendant container (which has real DOM focus)
|
|
|
|
finalFocusNode = aNode;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-03-05 19:43:50 -08:00
|
|
|
finalFocusAccessible = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fire focus only if it changes, but always fire focus events when aForceEvent == PR_TRUE
|
|
|
|
if (gLastFocusedNode == finalFocusNode && !aForceEvent) {
|
2007-04-09 06:40:25 -07:00
|
|
|
return PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-03-05 19:43:50 -08:00
|
|
|
if (!finalFocusAccessible) {
|
2010-06-11 01:23:18 -07:00
|
|
|
finalFocusAccessible = GetAccService()->GetAccessible(finalFocusNode);
|
2008-03-05 19:43:50 -08:00
|
|
|
// For activedescendant, the ARIA spec does not require that the user agent
|
2010-06-15 07:53:36 -07:00
|
|
|
// checks whether finalFocusNode is actually a DOM descendant of the element
|
|
|
|
// with the aria-activedescendant attribute.
|
2008-03-05 19:43:50 -08:00
|
|
|
if (!finalFocusAccessible) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-17 03:10:43 -07:00
|
|
|
gLastFocusedAccessiblesState = nsAccUtils::State(finalFocusAccessible);
|
|
|
|
PRUint32 role = nsAccUtils::Role(finalFocusAccessible);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (role == nsIAccessibleRole::ROLE_MENUITEM) {
|
2007-08-20 20:16:27 -07:00
|
|
|
if (!mCurrentARIAMenubar) { // Entering menus
|
2009-03-07 07:38:58 -08:00
|
|
|
// The natural role is the role that this type of element normally has
|
2010-09-04 19:14:01 -07:00
|
|
|
if (role != finalFocusAccessible->NativeRole()) { // Must be a DHTML menuitem
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *menuBarAccessible =
|
2008-10-16 02:12:05 -07:00
|
|
|
nsAccUtils::GetAncestorWithRole(finalFocusAccessible,
|
|
|
|
nsIAccessibleRole::ROLE_MENUBAR);
|
2010-06-11 01:23:18 -07:00
|
|
|
if (menuBarAccessible) {
|
|
|
|
mCurrentARIAMenubar = menuBarAccessible->GetNode();
|
2007-11-09 10:44:18 -08:00
|
|
|
if (mCurrentARIAMenubar) {
|
2010-08-24 19:08:28 -07:00
|
|
|
nsRefPtr<AccEvent> menuStartEvent =
|
|
|
|
new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
|
|
|
|
menuBarAccessible, PR_FALSE, aIsFromUserInput,
|
|
|
|
AccEvent::eAllowDupes);
|
2010-06-15 07:53:36 -07:00
|
|
|
if (menuStartEvent) {
|
|
|
|
FireDelayedAccessibleEvent(menuStartEvent);
|
|
|
|
}
|
2007-11-09 10:44:18 -08:00
|
|
|
}
|
2007-08-20 20:16:27 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-08-20 20:16:27 -07:00
|
|
|
else if (mCurrentARIAMenubar) {
|
2010-08-24 19:08:28 -07:00
|
|
|
nsRefPtr<AccEvent> menuEndEvent =
|
|
|
|
new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
|
|
|
|
PR_FALSE, aIsFromUserInput, AccEvent::eAllowDupes);
|
2007-08-20 20:16:27 -07:00
|
|
|
if (menuEndEvent) {
|
2008-03-17 01:13:10 -07:00
|
|
|
FireDelayedAccessibleEvent(menuEndEvent);
|
2007-08-20 20:16:27 -07:00
|
|
|
}
|
|
|
|
mCurrentARIAMenubar = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-04-19 23:10:25 -07:00
|
|
|
nsCOMPtr<nsIContent> focusContent = do_QueryInterface(finalFocusNode);
|
2008-02-08 18:28:01 -08:00
|
|
|
nsIFrame *focusFrame = nsnull;
|
|
|
|
if (focusContent) {
|
2010-05-17 06:42:32 -07:00
|
|
|
nsIPresShell *shell = nsCoreUtils::GetPresShellFor(finalFocusNode);
|
2009-04-19 23:10:25 -07:00
|
|
|
|
|
|
|
NS_ASSERTION(shell, "No pres shell for final focus node!");
|
|
|
|
if (!shell)
|
|
|
|
return PR_FALSE;
|
|
|
|
|
2009-12-24 13:20:05 -08:00
|
|
|
focusFrame = focusContent->GetPrimaryFrame();
|
2008-02-08 18:28:01 -08:00
|
|
|
}
|
2009-04-19 23:10:25 -07:00
|
|
|
|
|
|
|
NS_IF_RELEASE(gLastFocusedNode);
|
|
|
|
gLastFocusedNode = finalFocusNode;
|
|
|
|
NS_IF_ADDREF(gLastFocusedNode);
|
|
|
|
|
2008-02-08 18:28:01 -08:00
|
|
|
gLastFocusedFrameType = (focusFrame && focusFrame->GetStyleVisibility()->IsVisible()) ? focusFrame->GetType() : 0;
|
|
|
|
|
2010-03-17 00:10:52 -07:00
|
|
|
// Coalesce focus events from the same document, because DOM focus event might
|
|
|
|
// be fired for the document node and then for the focused DOM element.
|
2009-09-02 19:01:18 -07:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
|
2010-08-24 19:08:28 -07:00
|
|
|
finalFocusNode, AccEvent::eCoalesceFromSameDocument,
|
2010-01-20 03:16:32 -08:00
|
|
|
aIsAsynch, aIsFromUserInput);
|
2007-04-09 06:40:25 -07:00
|
|
|
|
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-01-25 07:08:08 -08:00
|
|
|
void
|
|
|
|
nsRootAccessible::FireCurrentFocusEvent()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-01-25 07:08:08 -08:00
|
|
|
if (IsDefunct())
|
|
|
|
return;
|
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
// Simulate a focus event so that we can reuse code that fires focus for
|
|
|
|
// container children like treeitems.
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCOMPtr<nsINode> focusedNode = GetCurrentFocus();
|
2007-04-12 07:47:55 -07:00
|
|
|
if (!focusedNode) {
|
|
|
|
return; // No current focus
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(mDocument);
|
|
|
|
if (docEvent) {
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
|
|
|
if (NS_SUCCEEDED(docEvent->CreateEvent(NS_LITERAL_STRING("Events"),
|
|
|
|
getter_AddRefs(event))) &&
|
|
|
|
NS_SUCCEEDED(event->InitEvent(NS_LITERAL_STRING("focus"), PR_TRUE, PR_TRUE))) {
|
2010-06-11 01:23:18 -07:00
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(focusedNode));
|
|
|
|
privateEvent->SetTarget(target);
|
|
|
|
HandleEvent(event);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIDOMEventListener
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-06-30 19:18:08 -07:00
|
|
|
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aEvent));
|
|
|
|
NS_ENSURE_STATE(nsevent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
|
|
|
|
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
|
|
|
|
nsCOMPtr<nsINode> origTarget(do_QueryInterface(domEventTarget));
|
|
|
|
NS_ENSURE_STATE(origTarget);
|
2009-12-10 11:12:19 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsAutoString eventType;
|
|
|
|
aEvent->GetType(eventType);
|
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCOMPtr<nsIWeakReference> weakShell =
|
2010-06-30 19:18:08 -07:00
|
|
|
nsCoreUtils::GetWeakShellFor(origTarget);
|
2010-06-11 01:23:18 -07:00
|
|
|
if (!weakShell)
|
2007-11-30 11:47:16 -08:00
|
|
|
return NS_OK;
|
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
nsAccessible* accessible =
|
|
|
|
GetAccService()->GetAccessibleOrContainer(origTarget, weakShell);
|
2008-12-03 01:04:02 -08:00
|
|
|
|
|
|
|
if (eventType.EqualsLiteral("popuphiding"))
|
2010-06-30 19:18:08 -07:00
|
|
|
return HandlePopupHidingEvent(origTarget, accessible);
|
2008-12-03 01:04:02 -08:00
|
|
|
|
2010-05-11 23:47:35 -07:00
|
|
|
if (!accessible)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
nsINode* targetNode = accessible->GetNode();
|
|
|
|
nsIContent* targetContent = targetNode->IsElement() ?
|
|
|
|
targetNode->AsElement() : nsnull;
|
2008-01-23 15:49:10 -08:00
|
|
|
#ifdef MOZ_XUL
|
2010-06-30 19:18:08 -07:00
|
|
|
PRBool isTree = targetContent ?
|
|
|
|
targetContent->NodeInfo()->Equals(nsAccessibilityAtoms::tree,
|
|
|
|
kNameSpaceID_XUL) : PR_FALSE;
|
|
|
|
|
2008-06-15 23:16:18 -07:00
|
|
|
if (isTree) {
|
2010-04-26 20:16:41 -07:00
|
|
|
nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(accessible);
|
2008-06-15 23:16:18 -07:00
|
|
|
NS_ASSERTION(treeAcc,
|
2009-06-29 08:38:17 -07:00
|
|
|
"Accessible for xul:tree isn't nsXULTreeAccessible.");
|
2008-06-15 23:16:18 -07:00
|
|
|
|
|
|
|
if (treeAcc) {
|
2009-06-29 08:38:17 -07:00
|
|
|
if (eventType.EqualsLiteral("TreeViewChanged")) {
|
|
|
|
treeAcc->TreeViewChanged();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2008-06-15 23:16:18 -07:00
|
|
|
|
|
|
|
if (eventType.EqualsLiteral("TreeRowCountChanged"))
|
|
|
|
return HandleTreeRowCountChangedEvent(aEvent, treeAcc);
|
|
|
|
|
|
|
|
if (eventType.EqualsLiteral("TreeInvalidated"))
|
|
|
|
return HandleTreeInvalidatedEvent(aEvent, treeAcc);
|
|
|
|
}
|
|
|
|
}
|
2008-01-23 15:49:10 -08:00
|
|
|
#endif
|
2007-12-11 00:18:04 -08:00
|
|
|
|
2007-04-17 05:39:10 -07:00
|
|
|
if (eventType.EqualsLiteral("RadioStateChange")) {
|
2008-10-17 03:10:43 -07:00
|
|
|
PRUint32 state = nsAccUtils::State(accessible);
|
2007-05-16 01:21:12 -07:00
|
|
|
|
|
|
|
// radiogroup in prefWindow is exposed as a list,
|
|
|
|
// and panebutton is exposed as XULListitem in A11y.
|
2008-11-03 19:37:46 -08:00
|
|
|
// nsXULListitemAccessible::GetStateInternal uses STATE_SELECTED in this case,
|
2007-05-16 01:21:12 -07:00
|
|
|
// so we need to check nsIAccessibleStates::STATE_SELECTED also.
|
|
|
|
PRBool isEnabled = (state & (nsIAccessibleStates::STATE_CHECKED |
|
|
|
|
nsIAccessibleStates::STATE_SELECTED)) != 0;
|
2007-04-17 05:39:10 -07:00
|
|
|
|
2010-08-24 19:08:28 -07:00
|
|
|
nsRefPtr<AccEvent> accEvent =
|
|
|
|
new AccStateChangeEvent(accessible, nsIAccessibleStates::STATE_CHECKED,
|
|
|
|
PR_FALSE, isEnabled);
|
2010-01-18 08:17:01 -08:00
|
|
|
nsEventShell::FireEvent(accEvent);
|
2007-04-17 05:39:10 -07:00
|
|
|
|
|
|
|
if (isEnabled)
|
2010-06-30 19:18:08 -07:00
|
|
|
FireAccessibleFocusEvent(accessible, targetNode, aEvent);
|
2007-04-17 05:39:10 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eventType.EqualsLiteral("CheckboxStateChange")) {
|
2008-10-17 03:10:43 -07:00
|
|
|
PRUint32 state = nsAccUtils::State(accessible);
|
2007-04-17 05:39:10 -07:00
|
|
|
|
2007-10-05 11:53:46 -07:00
|
|
|
PRBool isEnabled = !!(state & nsIAccessibleStates::STATE_CHECKED);
|
2007-04-17 05:39:10 -07:00
|
|
|
|
2010-08-24 19:08:28 -07:00
|
|
|
nsRefPtr<AccEvent> accEvent =
|
|
|
|
new AccStateChangeEvent(accessible, nsIAccessibleStates::STATE_CHECKED,
|
|
|
|
PR_FALSE, isEnabled);
|
2007-04-17 05:39:10 -07:00
|
|
|
|
2010-01-18 08:17:01 -08:00
|
|
|
nsEventShell::FireEvent(accEvent);
|
|
|
|
return NS_OK;
|
2007-04-17 05:39:10 -07:00
|
|
|
}
|
|
|
|
|
2010-05-11 23:47:35 -07:00
|
|
|
nsAccessible *treeItemAccessible = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
// If it's a tree element, need the currently selected item
|
2008-01-23 15:49:10 -08:00
|
|
|
if (isTree) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
|
2010-06-30 19:18:08 -07:00
|
|
|
do_QueryInterface(targetNode);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (multiSelect) {
|
|
|
|
PRInt32 treeIndex = -1;
|
|
|
|
multiSelect->GetCurrentIndex(&treeIndex);
|
|
|
|
if (treeIndex >= 0) {
|
2010-04-26 20:16:41 -07:00
|
|
|
nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(accessible);
|
2009-08-19 23:45:19 -07:00
|
|
|
if (treeAcc) {
|
2010-03-10 02:26:11 -08:00
|
|
|
treeItemAccessible = treeAcc->GetTreeItemAccessible(treeIndex);
|
2009-06-29 08:38:17 -07:00
|
|
|
if (treeItemAccessible)
|
|
|
|
accessible = treeItemAccessible;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MOZ_XUL
|
2007-04-17 05:39:10 -07:00
|
|
|
if (treeItemAccessible && eventType.EqualsLiteral("OpenStateChange")) {
|
2008-10-17 03:10:43 -07:00
|
|
|
PRUint32 state = nsAccUtils::State(accessible); // collapsed/expanded changed
|
2007-04-17 05:39:10 -07:00
|
|
|
PRBool isEnabled = (state & nsIAccessibleStates::STATE_EXPANDED) != 0;
|
|
|
|
|
2010-08-24 19:08:28 -07:00
|
|
|
nsRefPtr<AccEvent> accEvent =
|
|
|
|
new AccStateChangeEvent(accessible, nsIAccessibleStates::STATE_EXPANDED,
|
|
|
|
PR_FALSE, isEnabled);
|
2010-01-18 08:17:01 -08:00
|
|
|
nsEventShell::FireEvent(accEvent);
|
|
|
|
return NS_OK;
|
2007-04-09 21:37:52 -07:00
|
|
|
}
|
2007-04-17 05:39:10 -07:00
|
|
|
|
|
|
|
if (treeItemAccessible && eventType.EqualsLiteral("select")) {
|
2007-04-09 21:37:52 -07:00
|
|
|
// If multiselect tree, we should fire selectionadd or selection removed
|
2010-06-30 19:18:08 -07:00
|
|
|
if (gLastFocusedNode == targetNode) {
|
2007-04-09 21:37:52 -07:00
|
|
|
nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel =
|
2010-06-30 19:18:08 -07:00
|
|
|
do_QueryInterface(targetNode);
|
2007-04-09 21:37:52 -07:00
|
|
|
nsAutoString selType;
|
|
|
|
multiSel->GetSelType(selType);
|
|
|
|
if (selType.IsEmpty() || !selType.EqualsLiteral("single")) {
|
|
|
|
// XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
|
|
|
|
// for each tree item. Perhaps each tree item will need to cache its
|
|
|
|
// selection state and fire an event after a DOM "select" event when
|
|
|
|
// that state changes. nsXULTreeAccessible::UpdateTreeSelection();
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
|
|
|
|
accessible);
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-04-09 21:37:52 -07:00
|
|
|
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION,
|
|
|
|
treeItemAccessible);
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2007-04-09 21:37:52 -07:00
|
|
|
else
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2007-04-09 21:37:52 -07:00
|
|
|
if (eventType.EqualsLiteral("focus")) {
|
2010-06-30 19:18:08 -07:00
|
|
|
if (targetNode == mDocument && mDocument != gLastFocusedNode) {
|
2008-02-06 12:34:35 -08:00
|
|
|
// Got focus event for the window, we will make sure that an accessible
|
|
|
|
// focus event for initial focus is fired. We do this on a short timer
|
|
|
|
// because the initial focus may not have been set yet.
|
2010-01-25 07:08:08 -08:00
|
|
|
NS_DISPATCH_RUNNABLEMETHOD(FireCurrentFocusEvent, this)
|
2008-02-06 12:34:35 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Keep a reference to the target node. We might want to change
|
|
|
|
// it to the individual radio button or selected item, and send
|
|
|
|
// the focus event to that.
|
2010-06-30 19:18:08 -07:00
|
|
|
nsCOMPtr<nsINode> focusedItem = targetNode;
|
2007-04-09 21:37:52 -07:00
|
|
|
if (!treeItemAccessible) {
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlElement> selectControl =
|
2010-06-30 19:18:08 -07:00
|
|
|
do_QueryInterface(targetNode);
|
2007-04-09 21:37:52 -07:00
|
|
|
if (selectControl) {
|
|
|
|
nsCOMPtr<nsIDOMXULMenuListElement> menuList =
|
2010-06-30 19:18:08 -07:00
|
|
|
do_QueryInterface(targetNode);
|
2007-04-09 21:37:52 -07:00
|
|
|
if (!menuList) {
|
|
|
|
// Don't do this for menu lists, the items only get focused
|
|
|
|
// when the list is open, based on DOMMenuitemActive events
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
|
|
|
|
selectControl->GetSelectedItem(getter_AddRefs(selectedItem));
|
|
|
|
if (selectedItem)
|
|
|
|
focusedItem = do_QueryInterface(selectedItem);
|
|
|
|
|
|
|
|
if (!focusedItem)
|
|
|
|
return NS_OK;
|
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
accessible = GetAccService()->GetAccessibleInWeakShell(focusedItem,
|
|
|
|
weakShell);
|
2007-04-09 21:37:52 -07:00
|
|
|
if (!accessible)
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FireAccessibleFocusEvent(accessible, focusedItem, aEvent);
|
|
|
|
}
|
2010-03-12 20:24:51 -08:00
|
|
|
else if (eventType.EqualsLiteral("blur")) {
|
2010-03-13 00:41:43 -08:00
|
|
|
NS_IF_RELEASE(gLastFocusedNode);
|
2010-03-12 20:24:51 -08:00
|
|
|
gLastFocusedFrameType = nsnull;
|
|
|
|
gLastFocusedAccessiblesState = 0;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
else if (eventType.EqualsLiteral("AlertActive")) {
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-28 23:53:50 -07:00
|
|
|
else if (eventType.EqualsLiteral("popupshown")) {
|
2008-12-03 01:04:02 -08:00
|
|
|
HandlePopupShownEvent(accessible);
|
2007-05-21 06:53:57 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
else if (eventType.EqualsLiteral("DOMMenuInactive")) {
|
2008-10-17 03:10:43 -07:00
|
|
|
if (nsAccUtils::Role(accessible) == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
|
|
|
|
accessible);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2007-04-09 21:37:52 -07:00
|
|
|
else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
|
2008-03-05 19:43:50 -08:00
|
|
|
PRBool fireFocus = PR_FALSE;
|
2007-04-09 21:37:52 -07:00
|
|
|
if (!treeItemAccessible) {
|
2008-01-23 15:49:10 -08:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
if (isTree) {
|
|
|
|
return NS_OK; // Tree with nothing selected
|
|
|
|
}
|
|
|
|
#endif
|
2010-05-11 23:47:35 -07:00
|
|
|
nsIFrame* menuFrame = accessible->GetFrame();
|
2007-07-04 08:49:38 -07:00
|
|
|
NS_ENSURE_TRUE(menuFrame, NS_ERROR_FAILURE);
|
2008-10-31 20:58:07 -07:00
|
|
|
|
2009-01-12 11:20:59 -08:00
|
|
|
nsIMenuFrame* imenuFrame = do_QueryFrame(menuFrame);
|
2008-03-05 19:43:50 -08:00
|
|
|
if (imenuFrame)
|
|
|
|
fireFocus = PR_TRUE;
|
2007-07-23 00:46:48 -07:00
|
|
|
// QI failed for nsIMenuFrame means it's not on menu bar
|
|
|
|
if (imenuFrame && imenuFrame->IsOnMenuBar() &&
|
|
|
|
!imenuFrame->IsOnActiveMenuBar()) {
|
|
|
|
// It is a top level menuitem. Only fire a focus event when the menu bar
|
|
|
|
// is active.
|
|
|
|
return NS_OK;
|
2007-04-09 21:37:52 -07:00
|
|
|
} else {
|
2010-05-11 23:47:35 -07:00
|
|
|
nsAccessible *containerAccessible = accessible->GetParent();
|
2007-07-04 08:49:38 -07:00
|
|
|
NS_ENSURE_TRUE(containerAccessible, NS_ERROR_FAILURE);
|
2007-04-09 21:37:52 -07:00
|
|
|
// It is not top level menuitem
|
|
|
|
// Only fire focus event if it is not inside collapsed popup
|
2007-10-25 22:30:23 -07:00
|
|
|
// and not a listitem of a combo box
|
2008-10-17 03:10:43 -07:00
|
|
|
if (nsAccUtils::State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED) {
|
2010-05-11 23:47:35 -07:00
|
|
|
nsAccessible *containerParent = containerAccessible->GetParent();
|
2007-10-25 22:30:23 -07:00
|
|
|
NS_ENSURE_TRUE(containerParent, NS_ERROR_FAILURE);
|
2008-10-17 03:10:43 -07:00
|
|
|
if (nsAccUtils::Role(containerParent) != nsIAccessibleRole::ROLE_COMBOBOX) {
|
2007-10-25 22:30:23 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
2007-04-07 11:48:29 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-02-27 08:22:41 -08:00
|
|
|
if (!fireFocus) {
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCOMPtr<nsINode> realFocusedNode = GetCurrentFocus();
|
2010-08-24 19:08:43 -07:00
|
|
|
nsIContent* realFocusedContent =
|
|
|
|
realFocusedNode->IsElement() ? realFocusedNode->AsElement() : nsnull;
|
2010-06-30 19:18:08 -07:00
|
|
|
nsIContent* containerContent = targetContent;
|
2008-02-27 08:22:41 -08:00
|
|
|
while (containerContent) {
|
|
|
|
nsCOMPtr<nsIDOMXULPopupElement> popup = do_QueryInterface(containerContent);
|
|
|
|
if (popup || containerContent == realFocusedContent) {
|
|
|
|
// If we're inside the focus or a popup we can fire focus events
|
|
|
|
// for the changed active item
|
2008-03-05 19:43:50 -08:00
|
|
|
fireFocus = PR_TRUE;
|
|
|
|
break;
|
2008-02-27 08:22:41 -08:00
|
|
|
}
|
|
|
|
containerContent = containerContent->GetParent();
|
|
|
|
}
|
|
|
|
}
|
2008-03-05 19:43:50 -08:00
|
|
|
if (fireFocus) {
|
2010-01-20 03:16:32 -08:00
|
|
|
// Always asynch, always from user input.
|
2010-06-30 19:18:08 -07:00
|
|
|
FireAccessibleFocusEvent(accessible, targetNode, aEvent, PR_TRUE,
|
2010-01-20 03:16:32 -08:00
|
|
|
PR_TRUE, eFromUserInput);
|
2008-03-05 19:43:50 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-10 18:44:44 -07:00
|
|
|
else if (eventType.EqualsLiteral("DOMMenuBarActive")) { // Always asynch, always from user input
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START,
|
2010-01-20 03:16:32 -08:00
|
|
|
accessible, PR_TRUE, eFromUserInput);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-08-10 18:44:44 -07:00
|
|
|
else if (eventType.EqualsLiteral("DOMMenuBarInactive")) { // Always asynch, always from user input
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END,
|
2010-01-20 03:16:32 -08:00
|
|
|
accessible, PR_TRUE, eFromUserInput);
|
2007-03-22 10:30:00 -07:00
|
|
|
FireCurrentFocusEvent();
|
|
|
|
}
|
|
|
|
else if (eventType.EqualsLiteral("ValueChange")) {
|
2009-09-02 19:01:18 -07:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
|
2010-08-24 19:08:28 -07:00
|
|
|
targetNode, AccEvent::eRemoveDupes);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-12-10 19:30:02 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
else if (eventType.EqualsLiteral("mouseover")) {
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
|
|
|
|
accessible);
|
2007-12-10 19:30:02 -08:00
|
|
|
}
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsAccessNode
|
|
|
|
|
2010-06-11 21:04:35 -07:00
|
|
|
void
|
2008-10-31 20:58:07 -07:00
|
|
|
nsRootAccessible::Shutdown()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-10-10 09:51:45 -07:00
|
|
|
// Called manually or by nsAccessNode::LastRelease()
|
2010-06-11 21:04:35 -07:00
|
|
|
if (!mWeakShell)
|
|
|
|
return; // Already shutdown
|
2007-10-10 09:51:45 -07:00
|
|
|
|
2007-08-20 20:16:27 -07:00
|
|
|
mCurrentARIAMenubar = nsnull;
|
|
|
|
|
2010-06-11 21:04:35 -07:00
|
|
|
nsDocAccessibleWrap::Shutdown();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
// nsRootAccessible protected member
|
2007-03-22 10:30:00 -07:00
|
|
|
already_AddRefed<nsIDocShellTreeItem>
|
|
|
|
nsRootAccessible::GetContentDocShell(nsIDocShellTreeItem *aStart)
|
|
|
|
{
|
|
|
|
if (!aStart) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 itemType;
|
|
|
|
aStart->GetItemType(&itemType);
|
|
|
|
if (itemType == nsIDocShellTreeItem::typeContent) {
|
2010-06-08 09:39:58 -07:00
|
|
|
nsDocAccessible *accDoc = nsAccUtils::GetDocAccessibleFor(aStart);
|
2009-02-27 02:47:15 -08:00
|
|
|
|
|
|
|
// Hidden documents don't have accessibles (like SeaMonkey's sidebar),
|
|
|
|
// they are of no interest for a11y.
|
|
|
|
if (!accDoc)
|
|
|
|
return nsnull;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If ancestor chain of accessibles is not completely visible,
|
|
|
|
// don't use this one. This happens for example if it's inside
|
|
|
|
// a background tab (tabbed browsing)
|
2010-06-08 09:39:58 -07:00
|
|
|
nsAccessible *parent = accDoc->GetParent();
|
|
|
|
while (parent) {
|
|
|
|
if (nsAccUtils::State(parent) & nsIAccessibleStates::STATE_INVISIBLE)
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
2008-10-17 03:10:43 -07:00
|
|
|
|
2010-06-08 09:39:58 -07:00
|
|
|
if (parent == this)
|
2007-08-29 18:15:16 -07:00
|
|
|
break; // Don't check past original root accessible we started with
|
2010-06-08 09:39:58 -07:00
|
|
|
|
|
|
|
parent = parent->GetParent();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(aStart);
|
|
|
|
return aStart;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(aStart));
|
|
|
|
if (treeNode) {
|
|
|
|
PRInt32 subDocuments;
|
|
|
|
treeNode->GetChildCount(&subDocuments);
|
|
|
|
for (PRInt32 count = 0; count < subDocuments; count ++) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItemChild, contentTreeItem;
|
|
|
|
treeNode->GetChildAt(count, getter_AddRefs(treeItemChild));
|
|
|
|
NS_ENSURE_TRUE(treeItemChild, nsnull);
|
|
|
|
contentTreeItem = GetContentDocShell(treeItemChild);
|
|
|
|
if (contentTreeItem) {
|
|
|
|
NS_ADDREF(aStart = contentTreeItem);
|
|
|
|
return aStart;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
// nsIAccessible method
|
2009-02-10 02:03:30 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsRootAccessible::GetRelationByType(PRUint32 aRelationType,
|
|
|
|
nsIAccessibleRelation **aRelation)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-02-10 02:03:30 -08:00
|
|
|
NS_ENSURE_ARG_POINTER(aRelation);
|
|
|
|
*aRelation = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
if (!mDocument || aRelationType != nsIAccessibleRelation::RELATION_EMBEDS) {
|
2009-02-10 02:03:30 -08:00
|
|
|
return nsDocAccessibleWrap::GetRelationByType(aRelationType, aRelation);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-09-05 00:39:09 -07:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem =
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCoreUtils::GetDocShellTreeItemFor(mDocument);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> contentTreeItem = GetContentDocShell(treeItem);
|
|
|
|
// there may be no content area, so we need a null check
|
|
|
|
if (contentTreeItem) {
|
2010-06-08 09:39:58 -07:00
|
|
|
nsDocAccessible *accDoc = nsAccUtils::GetDocAccessibleFor(contentTreeItem);
|
|
|
|
return nsRelUtils::AddTarget(aRelationType, aRelation, accDoc);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-02-10 02:03:30 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Protected members
|
|
|
|
|
2008-12-03 01:04:02 -08:00
|
|
|
nsresult
|
2010-06-11 01:23:18 -07:00
|
|
|
nsRootAccessible::HandlePopupShownEvent(nsAccessible *aAccessible)
|
2008-12-03 01:04:02 -08:00
|
|
|
{
|
|
|
|
PRUint32 role = nsAccUtils::Role(aAccessible);
|
|
|
|
|
|
|
|
if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
|
|
|
// Don't fire menupopup events for combobox and autocomplete lists.
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
|
|
|
|
aAccessible);
|
|
|
|
return NS_OK;
|
2008-12-03 01:04:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (role == nsIAccessibleRole::ROLE_TOOLTIP) {
|
|
|
|
// There is a single <xul:tooltip> node which Mozilla moves around.
|
|
|
|
// The accessible for it stays the same no matter where it moves.
|
|
|
|
// AT's expect to get an EVENT_SHOW for the tooltip.
|
|
|
|
// In event callback the tooltip's accessible will be ready.
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SHOW, aAccessible);
|
|
|
|
return NS_OK;
|
2008-12-03 01:04:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (role == nsIAccessibleRole::ROLE_COMBOBOX_LIST) {
|
|
|
|
// Fire expanded state change event for comboboxes and autocompeletes.
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *comboboxAcc = aAccessible->GetParent();
|
2008-12-03 01:04:02 -08:00
|
|
|
PRUint32 comboboxRole = nsAccUtils::Role(comboboxAcc);
|
|
|
|
if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
|
|
|
|
comboboxRole == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
|
2010-08-24 19:08:28 -07:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(comboboxAcc,
|
|
|
|
nsIAccessibleStates::STATE_EXPANDED,
|
|
|
|
PR_FALSE, PR_TRUE);
|
2008-12-03 01:04:02 -08:00
|
|
|
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2010-01-18 08:17:01 -08:00
|
|
|
nsEventShell::FireEvent(event);
|
|
|
|
return NS_OK;
|
2008-12-03 01:04:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2010-06-11 01:23:18 -07:00
|
|
|
nsRootAccessible::HandlePopupHidingEvent(nsINode *aNode,
|
|
|
|
nsAccessible *aAccessible)
|
2008-12-03 01:04:02 -08:00
|
|
|
{
|
|
|
|
// If accessible focus was on or inside popup that closes, then restore it
|
|
|
|
// to true current focus. This is the case when we've been getting
|
|
|
|
// DOMMenuItemActive events inside of a combo box that closes. The real focus
|
|
|
|
// is on the combo box. It's also the case when a popup gets focus in ATK --
|
|
|
|
// when it closes we need to fire an event to restore focus to where it was.
|
2010-01-27 03:43:25 -08:00
|
|
|
|
2008-12-03 01:04:02 -08:00
|
|
|
if (gLastFocusedNode &&
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCoreUtils::IsAncestorOf(aNode, gLastFocusedNode)) {
|
2008-12-03 01:04:02 -08:00
|
|
|
// Focus was on or inside of a popup that's being hidden
|
|
|
|
FireCurrentFocusEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fire expanded state change event for comboboxes and autocompletes.
|
|
|
|
if (!aAccessible)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
PRUint32 role = nsAccUtils::Role(aAccessible);
|
|
|
|
if (role != nsIAccessibleRole::ROLE_COMBOBOX_LIST)
|
|
|
|
return NS_OK;
|
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *comboboxAcc = aAccessible->GetParent();
|
2008-12-03 01:04:02 -08:00
|
|
|
PRUint32 comboboxRole = nsAccUtils::Role(comboboxAcc);
|
|
|
|
if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
|
|
|
|
comboboxRole == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
|
2010-08-24 19:08:28 -07:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(comboboxAcc,
|
|
|
|
nsIAccessibleStates::STATE_EXPANDED,
|
|
|
|
PR_FALSE, PR_FALSE);
|
2008-12-03 01:04:02 -08:00
|
|
|
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2010-01-18 08:17:01 -08:00
|
|
|
nsEventShell::FireEvent(event);
|
|
|
|
return NS_OK;
|
2008-12-03 01:04:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-09-05 04:30:19 -07:00
|
|
|
#ifdef MOZ_XUL
|
2008-02-08 04:55:57 -08:00
|
|
|
nsresult
|
|
|
|
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
2009-06-29 08:38:17 -07:00
|
|
|
nsXULTreeAccessible *aAccessible)
|
2008-02-08 04:55:57 -08:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
|
|
|
|
if (!dataEvent)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIVariant> indexVariant;
|
|
|
|
dataEvent->GetData(NS_LITERAL_STRING("index"),
|
|
|
|
getter_AddRefs(indexVariant));
|
|
|
|
if (!indexVariant)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIVariant> countVariant;
|
|
|
|
dataEvent->GetData(NS_LITERAL_STRING("count"),
|
|
|
|
getter_AddRefs(countVariant));
|
|
|
|
if (!countVariant)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
PRInt32 index, count;
|
|
|
|
indexVariant->GetAsInt32(&index);
|
|
|
|
countVariant->GetAsInt32(&count);
|
|
|
|
|
2009-06-29 08:38:17 -07:00
|
|
|
aAccessible->InvalidateCache(index, count);
|
|
|
|
return NS_OK;
|
2008-02-08 04:55:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
2009-06-29 08:38:17 -07:00
|
|
|
nsXULTreeAccessible *aAccessible)
|
2008-02-08 04:55:57 -08:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
|
|
|
|
if (!dataEvent)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
PRInt32 startRow = 0, endRow = -1, startCol = 0, endCol = -1;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIVariant> startRowVariant;
|
|
|
|
dataEvent->GetData(NS_LITERAL_STRING("startrow"),
|
|
|
|
getter_AddRefs(startRowVariant));
|
|
|
|
if (startRowVariant)
|
|
|
|
startRowVariant->GetAsInt32(&startRow);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIVariant> endRowVariant;
|
|
|
|
dataEvent->GetData(NS_LITERAL_STRING("endrow"),
|
|
|
|
getter_AddRefs(endRowVariant));
|
|
|
|
if (endRowVariant)
|
|
|
|
endRowVariant->GetAsInt32(&endRow);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIVariant> startColVariant;
|
|
|
|
dataEvent->GetData(NS_LITERAL_STRING("startcolumn"),
|
|
|
|
getter_AddRefs(startColVariant));
|
|
|
|
if (startColVariant)
|
|
|
|
startColVariant->GetAsInt32(&startCol);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIVariant> endColVariant;
|
|
|
|
dataEvent->GetData(NS_LITERAL_STRING("endcolumn"),
|
|
|
|
getter_AddRefs(endColVariant));
|
|
|
|
if (endColVariant)
|
|
|
|
endColVariant->GetAsInt32(&endCol);
|
|
|
|
|
2009-06-29 08:38:17 -07:00
|
|
|
aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
|
|
|
|
return NS_OK;
|
2008-02-08 04:55:57 -08:00
|
|
|
}
|
2008-09-05 04:30:19 -07:00
|
|
|
#endif
|
2008-02-08 04:55:57 -08:00
|
|
|
|