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
|
|
|
|
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"
|
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
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsRootAccessible::nsRootAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
|
2007-08-20 20:16:27 -07:00
|
|
|
nsDocAccessibleWrap(aDOMNode, 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
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute unsigned long accRole; */
|
2009-03-07 07:38:58 -08:00
|
|
|
nsresult
|
|
|
|
nsRootAccessible::GetRoleInternal(PRUint32 *aRole)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (!mDocument) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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")) {
|
|
|
|
*aRole = nsIAccessibleRole::ROLE_DIALOG; // Always at the root
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-07 07:38:58 -08:00
|
|
|
return nsDocAccessibleWrap::GetRoleInternal(aRole);
|
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 =
|
2008-10-15 18:52:58 -07:00
|
|
|
nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
|
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
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMWindow> domWin;
|
|
|
|
GetWindow(getter_AddRefs(domWin));
|
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
|
|
|
nsCOMPtr<nsIDocShellTreeItem> dsti = do_GetInterface(domWin);
|
|
|
|
if (dsti) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> root;
|
|
|
|
dsti->GetRootTreeItem(getter_AddRefs(root));
|
|
|
|
nsCOMPtr<nsIDOMWindow> rootWindow = do_GetInterface(root);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
|
|
|
if (fm && rootWindow) {
|
|
|
|
nsCOMPtr<nsIDOMWindow> activeWindow;
|
|
|
|
fm->GetActiveWindow(getter_AddRefs(activeWindow));
|
|
|
|
if (activeWindow == rootWindow)
|
2008-04-20 23:24:08 -07:00
|
|
|
*aExtraState |= nsIAccessibleStates::EXT_STATE_ACTIVE;
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsRootAccessible::GetChromeEventHandler(nsIDOMEventTarget **aChromeTarget)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMWindow> domWin;
|
|
|
|
GetWindow(getter_AddRefs(domWin));
|
|
|
|
nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(domWin));
|
|
|
|
nsCOMPtr<nsPIDOMEventTarget> chromeEventHandler;
|
|
|
|
if (privateDOMWindow) {
|
|
|
|
chromeEventHandler = privateDOMWindow->GetChromeEventHandler();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(chromeEventHandler));
|
|
|
|
|
|
|
|
*aChromeTarget = target;
|
|
|
|
NS_IF_ADDREF(*aChromeTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
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",
|
|
|
|
"DOMMenuBarInactive",
|
|
|
|
"DOMContentLoaded"
|
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> target;
|
|
|
|
GetChromeEventHandler(getter_AddRefs(target));
|
|
|
|
if (target) {
|
|
|
|
target->AddEventListener(NS_LITERAL_STRING("pagehide"), this, PR_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GetChromeEventHandler(getter_AddRefs(target));
|
|
|
|
if (target) {
|
|
|
|
target->RemoveEventListener(NS_LITERAL_STRING("pagehide"), this, PR_TRUE);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void nsRootAccessible::TryFireEarlyLoadEvent(nsIDOMNode *aDocNode)
|
|
|
|
{
|
|
|
|
// We can fire an early load event based on DOMContentLoaded unless we
|
|
|
|
// have subdocuments. For that we wait until WebProgressListener
|
|
|
|
// STATE_STOP handling in nsAccessibilityService.
|
|
|
|
|
|
|
|
// Note, we don't fire any page load finished events for chrome or for
|
|
|
|
// frame/iframe page loads during the initial complete page load -- that page
|
|
|
|
// load event for the entire content pane needs to stand alone.
|
|
|
|
|
|
|
|
// This also works for firing events for error pages
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem =
|
2008-10-15 18:52:58 -07:00
|
|
|
nsCoreUtils::GetDocShellTreeItemFor(aDocNode);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(treeItem, "No docshelltreeitem for aDocNode");
|
|
|
|
if (!treeItem) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PRInt32 itemType;
|
|
|
|
treeItem->GetItemType(&itemType);
|
|
|
|
if (itemType != nsIDocShellTreeItem::typeContent) {
|
|
|
|
return;
|
|
|
|
}
|
2007-09-24 18:19:03 -07:00
|
|
|
|
2008-02-08 05:03:14 -08:00
|
|
|
// The doc accessible should already be created as a result of the
|
|
|
|
// OnStateChange() for the initiation of page loading
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(treeItem));
|
|
|
|
if (treeNode) {
|
|
|
|
PRInt32 subDocuments;
|
|
|
|
treeNode->GetChildCount(&subDocuments);
|
|
|
|
if (subDocuments) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> rootContentTreeItem;
|
|
|
|
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(rootContentTreeItem));
|
|
|
|
NS_ASSERTION(rootContentTreeItem, "No root content tree item");
|
2008-02-26 00:51:10 -08:00
|
|
|
if (rootContentTreeItem == treeItem) {
|
|
|
|
// No frames or iframes, so we can fire the doc load finished event early
|
2009-09-02 19:01:18 -07:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD,
|
|
|
|
aDocNode);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-08 10:36:02 -08:00
|
|
|
PRBool
|
|
|
|
nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
|
|
|
|
nsIDOMNode *aNode,
|
|
|
|
nsIDOMEvent *aFocusEvent,
|
|
|
|
PRBool aForceEvent,
|
2010-01-20 03:16:32 -08:00
|
|
|
PRBool aIsAsynch,
|
|
|
|
EIsFromUserInput aIsFromUserInput)
|
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));
|
|
|
|
nsCOMPtr<nsIDOMNode> 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
|
|
|
|
realFocusedNode = aNode;
|
|
|
|
}
|
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
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> finalFocusNode = aNode;
|
|
|
|
nsCOMPtr<nsIAccessible> finalFocusAccessible = aAccessible;
|
2008-10-17 03:10:43 -07:00
|
|
|
nsCOMPtr<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)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
|
|
aNode->GetOwnerDocument(getter_AddRefs(domDoc));
|
2008-03-14 13:49:38 -07:00
|
|
|
if (!domDoc) { // Maybe the passed-in node actually is a doc
|
|
|
|
domDoc = do_QueryInterface(aNode);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!domDoc) {
|
2007-04-09 06:40:25 -07:00
|
|
|
return PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMElement> relatedEl;
|
|
|
|
domDoc->GetElementById(id, getter_AddRefs(relatedEl));
|
2007-04-27 08:17:07 -07:00
|
|
|
finalFocusNode = do_QueryInterface(relatedEl);
|
|
|
|
if (!finalFocusNode) {
|
2008-03-19 18:10:36 -07:00
|
|
|
// If aria-activedescendant is set to nonextistant ID, then treat as focus
|
|
|
|
// 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) {
|
|
|
|
GetAccService()->GetAccessibleFor(finalFocusNode, getter_AddRefs(finalFocusAccessible));
|
|
|
|
// For activedescendant, the ARIA spec does not require that the user agent
|
|
|
|
// checks whether finalFocusNode is actually a descendant of the element with
|
|
|
|
// the activedescendant attribute.
|
|
|
|
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
|
|
|
|
PRUint32 naturalRole = nsAccUtils::RoleInternal(finalFocusAccessible);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (role != naturalRole) { // Must be a DHTML menuitem
|
2007-11-09 10:44:18 -08:00
|
|
|
nsCOMPtr<nsIAccessible> menuBarAccessible =
|
2008-10-16 02:12:05 -07:00
|
|
|
nsAccUtils::GetAncestorWithRole(finalFocusAccessible,
|
|
|
|
nsIAccessibleRole::ROLE_MENUBAR);
|
2007-11-09 10:44:18 -08:00
|
|
|
nsCOMPtr<nsIAccessNode> menuBarAccessNode = do_QueryInterface(menuBarAccessible);
|
|
|
|
if (menuBarAccessNode) {
|
|
|
|
menuBarAccessNode->GetDOMNode(getter_AddRefs(mCurrentARIAMenubar));
|
|
|
|
if (mCurrentARIAMenubar) {
|
2010-01-18 08:16:07 -08:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START,
|
2010-01-20 03:16:32 -08:00
|
|
|
menuBarAccessible, PR_FALSE,
|
|
|
|
aIsFromUserInput);
|
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-01-27 03:42:44 -08:00
|
|
|
nsRefPtr<nsAccEvent> menuEndEvent =
|
2008-03-17 01:13:10 -07:00
|
|
|
new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
|
2010-01-20 03:16:32 -08:00
|
|
|
PR_FALSE, aIsFromUserInput, nsAccEvent::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) {
|
2008-10-17 03:10:43 -07:00
|
|
|
nsCOMPtr<nsIPresShell> shell =
|
2009-04-19 23:10:25 -07:00
|
|
|
nsCoreUtils::GetPresShellFor(finalFocusNode);
|
|
|
|
|
|
|
|
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-03-17 00:10:52 -07:00
|
|
|
finalFocusNode, nsAccEvent::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;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> focusedNode = GetCurrentFocus();
|
2007-04-12 07:47:55 -07:00
|
|
|
if (!focusedNode) {
|
|
|
|
return; // No current focus
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Simulate a focus event so that we can reuse code that fires focus for container children like treeitems
|
|
|
|
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))) {
|
|
|
|
// Get the target node we really want for the event.
|
|
|
|
nsIAccessibilityService* accService = GetAccService();
|
|
|
|
if (accService) {
|
|
|
|
nsCOMPtr<nsIDOMNode> targetNode;
|
|
|
|
accService->GetRelevantContentNodeFor(focusedNode,
|
|
|
|
getter_AddRefs(targetNode));
|
2010-03-17 22:44:57 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (targetNode) {
|
2010-03-17 22:44:57 -07:00
|
|
|
// If the focused element is document element or HTML body element
|
|
|
|
// then simulate the focus event for the document.
|
|
|
|
nsCOMPtr<nsIContent> targetContent(do_QueryInterface(targetNode));
|
|
|
|
if (targetContent) {
|
|
|
|
nsCOMPtr<nsIDOMNode> document =
|
|
|
|
do_QueryInterface(targetContent->GetOwnerDoc());
|
|
|
|
if (targetContent == nsCoreUtils::GetRoleContent(document)) {
|
|
|
|
HandleEventWithTarget(event, document);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise simulate the focus event for currently focused node.
|
2007-03-22 10:30:00 -07:00
|
|
|
HandleEventWithTarget(event, targetNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIDOMEventListener
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|
|
|
{
|
|
|
|
// Turn DOM events in accessibility events
|
|
|
|
// Get info about event and target
|
|
|
|
nsCOMPtr<nsIDOMNode> targetNode;
|
|
|
|
GetTargetNode(aEvent, getter_AddRefs(targetNode));
|
|
|
|
if (!targetNode)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
return HandleEventWithTarget(aEvent, targetNode);
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
|
|
|
|
// nsRootAccessible protected member
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
|
|
|
|
nsIDOMNode* aTargetNode)
|
|
|
|
{
|
|
|
|
nsAutoString eventType;
|
|
|
|
aEvent->GetType(eventType);
|
|
|
|
nsAutoString localName;
|
|
|
|
aTargetNode->GetLocalName(localName);
|
2008-01-23 15:49:10 -08:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
PRBool isTree = localName.EqualsLiteral("tree");
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef DEBUG_A11Y
|
|
|
|
// Very useful for debugging, please leave this here.
|
2007-04-09 21:37:52 -07:00
|
|
|
if (eventType.EqualsLiteral("AlertActive")) {
|
2007-03-22 10:30:00 -07:00
|
|
|
printf("\ndebugging %s events for %s", NS_ConvertUTF16toUTF8(eventType).get(), NS_ConvertUTF16toUTF8(localName).get());
|
|
|
|
}
|
|
|
|
if (localName.LowerCaseEqualsLiteral("textbox")) {
|
|
|
|
printf("\ndebugging %s events for %s", NS_ConvertUTF16toUTF8(eventType).get(), NS_ConvertUTF16toUTF8(localName).get());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsIAccessibilityService *accService = GetAccService();
|
|
|
|
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
|
|
|
|
|
2007-04-09 21:37:52 -07:00
|
|
|
if (eventType.EqualsLiteral("pagehide")) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// pagehide event can be fired under several conditions, such as HTML
|
|
|
|
// document going away, closing a window/dialog, and wizard page changing.
|
|
|
|
// We only destroy the accessible object when it's a document accessible,
|
|
|
|
// so that we don't destroy something still in use, like wizard page.
|
|
|
|
// And we only get cached document accessible to destroy, so that we don't
|
|
|
|
// create it just to destroy it.
|
2007-11-30 11:47:16 -08:00
|
|
|
nsCOMPtr<nsIDocument> doc(do_QueryInterface(aTargetNode));
|
|
|
|
nsCOMPtr<nsIAccessibleDocument> accDoc = GetDocAccessibleFor(doc);
|
2008-10-31 20:58:07 -07:00
|
|
|
if (accDoc) {
|
2010-04-26 20:16:41 -07:00
|
|
|
nsRefPtr<nsAccessNode> docAccNode = do_QueryObject(accDoc);
|
2008-10-31 20:58:07 -07:00
|
|
|
docAccNode->Shutdown();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-10-31 20:58:07 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-17 03:10:43 -07:00
|
|
|
nsCOMPtr<nsIPresShell> eventShell = nsCoreUtils::GetPresShellFor(aTargetNode);
|
2007-11-30 11:47:16 -08:00
|
|
|
if (!eventShell) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-04-09 21:37:52 -07:00
|
|
|
if (eventType.EqualsLiteral("DOMContentLoaded")) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Don't create the doc accessible until load scripts have a chance to set
|
|
|
|
// role attribute for <body> or <html> element, because the value of
|
|
|
|
// role attribute will be cached when the doc accessible is Init()'d
|
|
|
|
TryFireEarlyLoadEvent(aTargetNode);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-05-12 02:14:50 -07:00
|
|
|
nsCOMPtr<nsIAccessible> accessible;
|
|
|
|
accService->GetAccessibleInShell(aTargetNode, eventShell,
|
|
|
|
getter_AddRefs(accessible));
|
2008-12-03 01:04:02 -08:00
|
|
|
|
|
|
|
if (eventType.EqualsLiteral("popuphiding"))
|
|
|
|
return HandlePopupHidingEvent(aTargetNode, accessible);
|
|
|
|
|
2010-05-12 02:14:50 -07:00
|
|
|
nsRefPtr<nsAccessible> acc(do_QueryObject(accessible));
|
|
|
|
if (!acc)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2008-01-23 15:49:10 -08:00
|
|
|
#ifdef MOZ_XUL
|
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-01-18 08:17:01 -08:00
|
|
|
nsRefPtr<nsAccEvent> accEvent =
|
2007-04-17 05:39:10 -07:00
|
|
|
new nsAccStateChangeEvent(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)
|
|
|
|
FireAccessibleFocusEvent(accessible, aTargetNode, aEvent);
|
|
|
|
|
|
|
|
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-01-18 08:17:01 -08:00
|
|
|
nsRefPtr<nsAccEvent> accEvent =
|
2007-04-17 05:39:10 -07:00
|
|
|
new nsAccStateChangeEvent(accessible,
|
|
|
|
nsIAccessibleStates::STATE_CHECKED,
|
|
|
|
PR_FALSE, isEnabled);
|
|
|
|
|
2010-01-18 08:17:01 -08:00
|
|
|
nsEventShell::FireEvent(accEvent);
|
|
|
|
return NS_OK;
|
2007-04-17 05:39:10 -07:00
|
|
|
}
|
|
|
|
|
2010-05-12 02:14:50 -07:00
|
|
|
nsCOMPtr<nsIAccessible> treeItemAccessible;
|
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 =
|
|
|
|
do_QueryInterface(aTargetNode);
|
|
|
|
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-01-18 08:17:01 -08:00
|
|
|
nsRefPtr<nsAccEvent> accEvent =
|
2007-04-17 05:39:10 -07:00
|
|
|
new nsAccStateChangeEvent(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
|
|
|
|
if (gLastFocusedNode == aTargetNode) {
|
|
|
|
nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel =
|
|
|
|
do_QueryInterface(aTargetNode);
|
|
|
|
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")) {
|
2008-02-06 12:34:35 -08:00
|
|
|
if (aTargetNode == mDOMNode && mDOMNode != gLastFocusedNode) {
|
|
|
|
// 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.
|
|
|
|
nsCOMPtr<nsIDOMNode> focusedItem(aTargetNode);
|
2007-04-09 21:37:52 -07:00
|
|
|
|
|
|
|
if (!treeItemAccessible) {
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlElement> selectControl =
|
2007-03-22 10:30:00 -07:00
|
|
|
do_QueryInterface(aTargetNode);
|
2007-04-09 21:37:52 -07:00
|
|
|
if (selectControl) {
|
|
|
|
nsCOMPtr<nsIDOMXULMenuListElement> menuList =
|
|
|
|
do_QueryInterface(aTargetNode);
|
|
|
|
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-05-12 02:14:50 -07:00
|
|
|
accService->GetAccessibleInShell(focusedItem, eventShell,
|
|
|
|
getter_AddRefs(accessible));
|
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-12 02:14:50 -07:00
|
|
|
nsRefPtr<nsAccessNode> menuAccessNode = do_QueryObject(accessible);
|
|
|
|
|
|
|
|
nsIFrame* menuFrame = menuAccessNode->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-12 02:14:50 -07:00
|
|
|
nsCOMPtr<nsIAccessible> containerAccessible;
|
|
|
|
accessible->GetParent(getter_AddRefs(containerAccessible));
|
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-12 02:14:50 -07:00
|
|
|
nsCOMPtr<nsIAccessible> containerParent;
|
|
|
|
containerAccessible->GetParent(getter_AddRefs(containerParent));
|
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) {
|
|
|
|
nsCOMPtr<nsIDOMNode> realFocusedNode = GetCurrentFocus();
|
|
|
|
nsCOMPtr<nsIContent> realFocusedContent = do_QueryInterface(realFocusedNode);
|
|
|
|
nsCOMPtr<nsIContent> targetContent = do_QueryInterface(aTargetNode);
|
|
|
|
nsIContent *containerContent = targetContent;
|
|
|
|
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.
|
|
|
|
FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE,
|
|
|
|
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,
|
|
|
|
aTargetNode, nsAccEvent::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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsRootAccessible::GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode)
|
|
|
|
{
|
|
|
|
*aTargetNode = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aEvent));
|
|
|
|
|
|
|
|
if (!nsevent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
|
|
|
|
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
|
|
|
|
nsCOMPtr<nsIDOMNode> eventTarget(do_QueryInterface(domEventTarget));
|
|
|
|
if (!eventTarget)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIAccessibilityService* accService = GetAccService();
|
|
|
|
if (accService) {
|
|
|
|
nsresult rv = accService->GetRelevantContentNodeFor(eventTarget,
|
|
|
|
aTargetNode);
|
|
|
|
if (NS_SUCCEEDED(rv) && *aTargetNode)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aTargetNode = eventTarget);
|
|
|
|
}
|
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsAccessNode
|
|
|
|
|
2008-10-31 20:58:07 -07:00
|
|
|
nsresult
|
2007-06-01 20:01:38 -07:00
|
|
|
nsRootAccessible::Init()
|
|
|
|
{
|
2010-03-18 11:49:39 -07:00
|
|
|
nsApplicationAccessible *applicationAcc = GetApplicationAccessible();
|
|
|
|
NS_ENSURE_STATE(applicationAcc);
|
2007-06-01 20:01:38 -07:00
|
|
|
|
2010-03-18 11:49:39 -07:00
|
|
|
applicationAcc->AddRootAccessible(this);
|
2009-07-27 19:28:06 -07:00
|
|
|
|
2009-12-16 07:31:14 -08:00
|
|
|
return nsDocAccessibleWrap::Init();
|
2007-06-01 20:01:38 -07:00
|
|
|
}
|
|
|
|
|
2008-10-31 20:58:07 -07:00
|
|
|
nsresult
|
|
|
|
nsRootAccessible::Shutdown()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-10-10 09:51:45 -07:00
|
|
|
// Called manually or by nsAccessNode::LastRelease()
|
|
|
|
if (!mWeakShell) {
|
|
|
|
return NS_OK; // Already shutdown
|
|
|
|
}
|
|
|
|
|
2010-03-18 11:49:39 -07:00
|
|
|
nsApplicationAccessible *applicationAcc = GetApplicationAccessible();
|
|
|
|
NS_ENSURE_STATE(applicationAcc);
|
2007-06-01 20:01:38 -07:00
|
|
|
|
2010-03-18 11:49:39 -07:00
|
|
|
applicationAcc->RemoveRootAccessible(this);
|
2007-06-01 20:01:38 -07:00
|
|
|
|
2007-08-20 20:16:27 -07:00
|
|
|
mCurrentARIAMenubar = nsnull;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsDocAccessibleWrap::Shutdown();
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
nsCOMPtr<nsIAccessibleDocument> accDoc =
|
|
|
|
GetDocAccessibleFor(aStart, PR_TRUE);
|
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
|
|
|
nsCOMPtr<nsIAccessible> accessible = do_QueryInterface(accDoc);
|
2009-02-27 02:47:15 -08:00
|
|
|
|
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)
|
|
|
|
while (accessible) {
|
2008-10-17 03:10:43 -07:00
|
|
|
if (nsAccUtils::State(accessible) & nsIAccessibleStates::STATE_INVISIBLE)
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
2008-10-17 03:10:43 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIAccessible> ancestor;
|
|
|
|
accessible->GetParent(getter_AddRefs(ancestor));
|
2007-08-29 18:15:16 -07:00
|
|
|
if (ancestor == this) {
|
|
|
|
break; // Don't check past original root accessible we started with
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
accessible.swap(ancestor);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-05-19 19:41:33 -07:00
|
|
|
if (!mDOMNode || 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 =
|
2008-10-15 18:52:58 -07:00
|
|
|
nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
|
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) {
|
|
|
|
nsCOMPtr<nsIAccessibleDocument> accDoc =
|
|
|
|
GetDocAccessibleFor(contentTreeItem, PR_TRUE);
|
2008-10-17 03:09:22 -07:00
|
|
|
|
2009-02-10 02:03:30 -08:00
|
|
|
nsCOMPtr<nsIAccessible> acc(do_QueryInterface(accDoc));
|
|
|
|
return nsRelUtils::AddTarget(aRelationType, aRelation, acc);
|
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
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsAccessible
|
|
|
|
|
2010-01-11 06:14:06 -08:00
|
|
|
nsAccessible*
|
2009-12-10 11:12:19 -08:00
|
|
|
nsRootAccessible::GetParent()
|
|
|
|
{
|
|
|
|
// Parent has been setted in nsApplicationAccesible::AddRootAccessible()
|
|
|
|
// when root accessible was intialized.
|
|
|
|
return mParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsDocAccessible
|
|
|
|
|
2009-06-24 19:08:53 -07:00
|
|
|
void
|
|
|
|
nsRootAccessible::FireDocLoadEvents(PRUint32 aEventType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-06-24 19:08:53 -07:00
|
|
|
if (IsDefunct())
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
|
2008-10-15 18:52:58 -07:00
|
|
|
nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(docShellTreeItem, "No doc shell tree item for document");
|
2009-06-24 19:08:53 -07:00
|
|
|
if (!docShellTreeItem)
|
|
|
|
return;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 contentType;
|
|
|
|
docShellTreeItem->GetItemType(&contentType);
|
2009-06-24 19:08:53 -07:00
|
|
|
if (contentType == nsIDocShellTreeItem::typeContent)
|
|
|
|
nsDocAccessibleWrap::FireDocLoadEvents(aEventType); // Content might need to fire event
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Root chrome: don't fire event
|
|
|
|
mIsContentLoaded = (aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE ||
|
|
|
|
aEventType == nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED);
|
|
|
|
}
|
2008-02-08 04:55:57 -08:00
|
|
|
|
2009-12-10 11:12:19 -08:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Protected members
|
|
|
|
|
2008-12-03 01:04:02 -08:00
|
|
|
nsresult
|
|
|
|
nsRootAccessible::HandlePopupShownEvent(nsIAccessible *aAccessible)
|
|
|
|
{
|
|
|
|
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.
|
|
|
|
nsCOMPtr<nsIAccessible> comboboxAcc;
|
|
|
|
nsresult rv = aAccessible->GetParent(getter_AddRefs(comboboxAcc));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRUint32 comboboxRole = nsAccUtils::Role(comboboxAcc);
|
|
|
|
if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
|
|
|
|
comboboxRole == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
|
2010-01-18 08:17:01 -08:00
|
|
|
nsRefPtr<nsAccEvent> event =
|
2008-12-03 01:04:02 -08:00
|
|
|
new nsAccStateChangeEvent(comboboxAcc,
|
|
|
|
nsIAccessibleStates::STATE_EXPANDED,
|
|
|
|
PR_FALSE, PR_TRUE);
|
|
|
|
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2010-04-26 20:16:41 -07:00
|
|
|
nsRefPtr<nsAccessible> acc(do_QueryObject(comboboxAcc));
|
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
|
|
|
|
nsRootAccessible::HandlePopupHidingEvent(nsIDOMNode *aNode,
|
|
|
|
nsIAccessible *aAccessible)
|
|
|
|
{
|
|
|
|
// 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
|
|
|
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
|
|
|
|
nsCOMPtr<nsINode> lastFocusedNode(do_QueryInterface(gLastFocusedNode));
|
|
|
|
|
2008-12-03 01:04:02 -08:00
|
|
|
if (gLastFocusedNode &&
|
2010-01-27 03:43:25 -08:00
|
|
|
nsCoreUtils::IsAncestorOf(node, lastFocusedNode)) {
|
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;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessible> comboboxAcc;
|
|
|
|
nsresult rv = aAccessible->GetParent(getter_AddRefs(comboboxAcc));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRUint32 comboboxRole = nsAccUtils::Role(comboboxAcc);
|
|
|
|
if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
|
|
|
|
comboboxRole == nsIAccessibleRole::ROLE_AUTOCOMPLETE) {
|
2010-01-18 08:17:01 -08:00
|
|
|
nsRefPtr<nsAccEvent> event =
|
2008-12-03 01:04:02 -08:00
|
|
|
new nsAccStateChangeEvent(comboboxAcc,
|
|
|
|
nsIAccessibleStates::STATE_EXPANDED,
|
|
|
|
PR_FALSE, PR_FALSE);
|
|
|
|
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
|
|
|
|