2003-04-01 22:18:29 +00: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) 2003
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2004-04-17 21:52:36 +00:00
|
|
|
* Original Author: Aaron Leventhal (aaronl@netscape.com)
|
2003-04-01 22:18:29 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2004-04-17 21:52:36 +00:00
|
|
|
* 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"),
|
2003-04-01 22:18:29 +00:00
|
|
|
* 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 ***** */
|
|
|
|
|
2010-04-27 06:52:03 +00:00
|
|
|
#include "nsAccCache.h"
|
2005-06-10 13:57:27 +00:00
|
|
|
#include "nsAccessibilityAtoms.h"
|
2009-07-29 09:01:48 +00:00
|
|
|
#include "nsAccessibilityService.h"
|
2010-07-02 01:50:03 +00:00
|
|
|
#include "nsAccTreeWalker.h"
|
2010-04-27 06:52:03 +00:00
|
|
|
#include "nsAccUtils.h"
|
|
|
|
#include "nsRootAccessible.h"
|
|
|
|
#include "nsTextEquivUtils.h"
|
|
|
|
|
2006-04-12 15:43:32 +00:00
|
|
|
#include "nsIMutableArray.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#include "nsICommandManager.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIDocShellTreeItem.h"
|
2003-04-01 22:18:29 +00:00
|
|
|
#include "nsIDocument.h"
|
2005-01-28 02:35:26 +00:00
|
|
|
#include "nsIDOMAttr.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#include "nsIDOMCharacterData.h"
|
2003-04-01 22:18:29 +00:00
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsIDOMDocumentType.h"
|
2003-04-28 10:24:52 +00:00
|
|
|
#include "nsIDOMNSDocument.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#include "nsIDOMNSHTMLDocument.h"
|
2010-06-11 08:23:18 +00:00
|
|
|
#include "nsIDOMXULDocument.h"
|
2005-08-05 18:16:32 +00:00
|
|
|
#include "nsIDOMMutationEvent.h"
|
2005-11-28 23:56:44 +00:00
|
|
|
#include "nsPIDOMWindow.h"
|
2005-09-30 19:23:42 +00:00
|
|
|
#include "nsIDOMXULPopupElement.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#include "nsIEditingSession.h"
|
2005-07-25 21:40:31 +00:00
|
|
|
#include "nsIEventStateManager.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#include "nsIFrame.h"
|
2005-07-25 21:40:31 +00:00
|
|
|
#include "nsHTMLSelectAccessible.h"
|
2003-04-01 22:18:29 +00:00
|
|
|
#include "nsIInterfaceRequestorUtils.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsIPresShell.h"
|
2003-04-01 22:18:29 +00:00
|
|
|
#include "nsIServiceManager.h"
|
2007-02-12 19:46:41 +00:00
|
|
|
#include "nsIViewManager.h"
|
2009-09-03 03:57:41 +00:00
|
|
|
#include "nsIScrollableFrame.h"
|
2005-06-24 19:16:45 +00:00
|
|
|
#include "nsUnicharUtils.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsIWebNavigation.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 18:00:39 +00:00
|
|
|
#include "nsFocusManager.h"
|
2010-08-24 07:05:56 +00:00
|
|
|
#include "mozilla/dom/Element.h"
|
2003-05-15 08:37:38 +00:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
#include "nsIXULDocument.h"
|
|
|
|
#endif
|
2003-04-01 22:18:29 +00:00
|
|
|
|
2010-08-24 07:05:56 +00:00
|
|
|
namespace dom = mozilla::dom;
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Static member initialization
|
2003-04-01 22:18:29 +00:00
|
|
|
|
2007-09-18 21:36:41 +00:00
|
|
|
PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
|
|
|
|
|
2010-11-18 02:55:44 +00:00
|
|
|
static nsIAtom** kRelationAttrs[] =
|
|
|
|
{
|
|
|
|
&nsAccessibilityAtoms::aria_labelledby,
|
|
|
|
&nsAccessibilityAtoms::aria_describedby,
|
|
|
|
&nsAccessibilityAtoms::aria_owns,
|
|
|
|
&nsAccessibilityAtoms::aria_controls,
|
|
|
|
&nsAccessibilityAtoms::aria_flowto
|
|
|
|
};
|
|
|
|
|
|
|
|
static const PRUint32 kRelationAttrsLen = NS_ARRAY_LENGTH(kRelationAttrs);
|
2009-12-10 19:12:19 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructor/desctructor
|
|
|
|
|
2010-06-11 08:23:18 +00:00
|
|
|
nsDocAccessible::
|
|
|
|
nsDocAccessible(nsIDocument *aDocument, nsIContent *aRootContent,
|
|
|
|
nsIWeakReference *aShell) :
|
2010-09-17 03:23:17 +00:00
|
|
|
nsHyperTextAccessibleWrap(aRootContent, aShell),
|
2010-07-16 14:15:07 +00:00
|
|
|
mDocument(aDocument), mScrollPositionChangedTicks(0), mIsLoaded(PR_FALSE)
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
2010-11-18 02:55:44 +00:00
|
|
|
mDependentIDsHash.Init();
|
2009-08-11 06:59:05 +00:00
|
|
|
// XXX aaronl should we use an algorithm for the initial cache size?
|
2010-06-12 04:04:35 +00:00
|
|
|
mAccessibleCache.Init(kDefaultCacheSize);
|
2010-10-21 04:16:10 +00:00
|
|
|
mNodeToAccessibleMap.Init(kDefaultCacheSize);
|
2009-08-11 06:59:05 +00:00
|
|
|
|
2006-08-30 05:19:06 +00:00
|
|
|
// For GTK+ native window, we do nothing here.
|
2010-06-11 08:23:18 +00:00
|
|
|
if (!mDocument)
|
2006-08-30 05:19:06 +00:00
|
|
|
return;
|
|
|
|
|
2010-06-08 16:39:58 +00:00
|
|
|
// nsAccDocManager creates document accessible when scrollable frame is
|
|
|
|
// available already, it should be safe time to add scroll listener.
|
|
|
|
AddScrollListener();
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsDocAccessible::~nsDocAccessible()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
|
2008-08-06 12:19:56 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsISupports
|
2008-08-06 12:19:56 +00:00
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
2010-01-27 11:42:08 +00:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventQueue");
|
|
|
|
cb.NoteXPCOMChild(tmp->mEventQueue.get());
|
2009-09-07 16:46:56 +00:00
|
|
|
|
2010-09-09 14:44:56 +00:00
|
|
|
PRUint32 i, length = tmp->mChildDocuments.Length();
|
|
|
|
for (i = 0; i < length; ++i) {
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildDocuments[i]");
|
|
|
|
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mChildDocuments[i].get()));
|
|
|
|
}
|
|
|
|
|
2010-06-12 04:04:35 +00:00
|
|
|
CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
|
2008-08-06 12:19:56 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
2010-01-27 11:42:08 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventQueue)
|
2010-09-09 14:44:56 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mChildDocuments)
|
2010-11-18 02:55:44 +00:00
|
|
|
tmp->mDependentIDsHash.Clear();
|
2010-10-21 04:16:10 +00:00
|
|
|
tmp->mNodeToAccessibleMap.Clear();
|
2010-06-12 04:04:35 +00:00
|
|
|
ClearCache(tmp->mAccessibleCache);
|
2008-08-06 12:19:56 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDocAccessible)
|
2009-06-25 02:08:53 +00:00
|
|
|
NS_INTERFACE_MAP_STATIC_AMBIGUOUS(nsDocAccessible)
|
2003-05-15 08:37:38 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
|
2005-06-10 13:57:27 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
|
2006-07-02 07:23:10 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
2003-05-15 08:37:38 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
2009-06-25 02:08:53 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessibleDocument)
|
2010-06-11 08:23:18 +00:00
|
|
|
foundInterface = 0;
|
|
|
|
|
|
|
|
nsresult status;
|
|
|
|
if (!foundInterface) {
|
|
|
|
// HTML document accessible must inherit from nsHyperTextAccessible to get
|
|
|
|
// support text interfaces. XUL document accessible doesn't need this.
|
|
|
|
// However at some point we may push <body> to implement the interfaces and
|
|
|
|
// return nsDocAccessible to inherit from nsAccessibleWrap.
|
|
|
|
|
2010-11-18 19:45:45 +00:00
|
|
|
if (mDocument && mDocument->IsXUL())
|
2010-06-11 08:23:18 +00:00
|
|
|
status = nsAccessible::QueryInterface(aIID, (void**)&foundInterface);
|
|
|
|
else
|
|
|
|
status = nsHyperTextAccessible::QueryInterface(aIID,
|
|
|
|
(void**)&foundInterface);
|
|
|
|
} else {
|
|
|
|
NS_ADDREF(foundInterface);
|
|
|
|
status = NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aInstancePtr = foundInterface;
|
|
|
|
return status;
|
|
|
|
}
|
2003-05-15 08:37:38 +00:00
|
|
|
|
2006-06-21 13:29:10 +00:00
|
|
|
NS_IMPL_ADDREF_INHERITED(nsDocAccessible, nsHyperTextAccessible)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsDocAccessible, nsHyperTextAccessible)
|
2003-04-01 22:18:29 +00:00
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIAccessible
|
|
|
|
|
2008-10-10 12:26:55 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocAccessible::GetName(nsAString& aName)
|
2006-04-10 14:25:14 +00:00
|
|
|
{
|
2005-06-01 14:03:38 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
aName.Truncate();
|
2008-03-14 20:49:38 +00:00
|
|
|
if (mParent) {
|
|
|
|
rv = mParent->GetName(aName); // Allow owning iframe to override the name
|
2005-06-01 14:03:38 +00:00
|
|
|
}
|
|
|
|
if (aName.IsEmpty()) {
|
2008-10-10 12:26:55 +00:00
|
|
|
// Allow name via aria-labelledby or title attribute
|
|
|
|
rv = nsAccessible::GetName(aName);
|
2005-06-01 14:03:38 +00:00
|
|
|
}
|
2008-03-14 20:49:38 +00:00
|
|
|
if (aName.IsEmpty()) {
|
2008-04-15 15:17:59 +00:00
|
|
|
rv = GetTitle(aName); // Try title element
|
|
|
|
}
|
|
|
|
if (aName.IsEmpty()) { // Last resort: use URL
|
|
|
|
rv = GetURL(aName);
|
2005-08-17 19:08:26 +00:00
|
|
|
}
|
2005-06-01 14:03:38 +00:00
|
|
|
|
|
|
|
return rv;
|
2003-04-15 08:45:55 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsAccessible public method
|
2010-09-05 02:14:01 +00:00
|
|
|
PRUint32
|
|
|
|
nsDocAccessible::NativeRole()
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
2005-06-01 13:54:08 +00:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
|
2010-06-11 08:23:18 +00:00
|
|
|
nsCoreUtils::GetDocShellTreeItemFor(mDocument);
|
2005-06-01 13:54:08 +00:00
|
|
|
if (docShellTreeItem) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
|
|
|
|
docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
|
2007-06-14 17:12:50 +00:00
|
|
|
PRInt32 itemType;
|
|
|
|
docShellTreeItem->GetItemType(&itemType);
|
2005-06-01 13:54:08 +00:00
|
|
|
if (sameTypeRoot == docShellTreeItem) {
|
|
|
|
// Root of content or chrome tree
|
2010-09-05 02:14:01 +00:00
|
|
|
if (itemType == nsIDocShellTreeItem::typeChrome)
|
|
|
|
return nsIAccessibleRole::ROLE_CHROME_WINDOW;
|
|
|
|
|
|
|
|
if (itemType == nsIDocShellTreeItem::typeContent) {
|
2005-07-21 14:28:17 +00:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
|
2010-09-05 02:14:01 +00:00
|
|
|
if (xulDoc)
|
|
|
|
return nsIAccessibleRole::ROLE_APPLICATION;
|
2005-07-21 14:28:17 +00:00
|
|
|
#endif
|
2010-09-05 02:14:01 +00:00
|
|
|
return nsIAccessibleRole::ROLE_DOCUMENT;
|
2005-06-01 13:54:08 +00:00
|
|
|
}
|
|
|
|
}
|
2007-06-14 17:12:50 +00:00
|
|
|
else if (itemType == nsIDocShellTreeItem::typeContent) {
|
2010-09-05 02:14:01 +00:00
|
|
|
return nsIAccessibleRole::ROLE_DOCUMENT;
|
2007-06-14 17:12:50 +00:00
|
|
|
}
|
2005-06-01 13:54:08 +00:00
|
|
|
}
|
2006-04-10 14:25:14 +00:00
|
|
|
|
2010-09-05 02:14:01 +00:00
|
|
|
return nsIAccessibleRole::ROLE_PANE; // Fall back;
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsAccessible public method
|
2009-06-18 07:37:38 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
2009-06-18 07:37:38 +00:00
|
|
|
NS_ASSERTION(mDocument, "No document during initialization!");
|
|
|
|
if (!mDocument)
|
|
|
|
return;
|
2008-03-14 20:49:38 +00:00
|
|
|
|
|
|
|
mRoleMapEntry = aRoleMapEntry;
|
|
|
|
|
|
|
|
nsIDocument *parentDoc = mDocument->GetParentDocument();
|
2009-06-18 07:37:38 +00:00
|
|
|
if (!parentDoc)
|
2009-06-29 13:26:45 +00:00
|
|
|
return; // No parent document for the root document
|
2009-06-18 07:37:38 +00:00
|
|
|
|
2009-06-29 13:26:45 +00:00
|
|
|
// Allow use of ARIA role from outer to override
|
2008-03-14 20:49:38 +00:00
|
|
|
nsIContent *ownerContent = parentDoc->FindContentForSubDocument(mDocument);
|
2010-06-11 08:23:18 +00:00
|
|
|
if (ownerContent) {
|
|
|
|
nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(ownerContent);
|
2008-03-14 20:49:38 +00:00
|
|
|
if (roleMapEntry)
|
|
|
|
mRoleMapEntry = roleMapEntry; // Override
|
|
|
|
}
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
2007-07-02 06:14:11 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocAccessible::GetDescription(nsAString& aDescription)
|
|
|
|
{
|
2008-03-14 20:49:38 +00:00
|
|
|
if (mParent)
|
|
|
|
mParent->GetDescription(aDescription);
|
|
|
|
|
|
|
|
if (aDescription.IsEmpty()) {
|
|
|
|
nsAutoString description;
|
2009-02-19 07:06:14 +00:00
|
|
|
nsTextEquivUtils::
|
|
|
|
GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
|
|
|
|
description);
|
2008-03-14 20:49:38 +00:00
|
|
|
aDescription = description;
|
|
|
|
}
|
|
|
|
|
2007-07-02 06:14:11 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsAccessible public method
|
2008-11-04 03:37:46 +00:00
|
|
|
nsresult
|
|
|
|
nsDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
2010-06-11 08:23:18 +00:00
|
|
|
*aState = 0;
|
|
|
|
|
|
|
|
if (IsDefunct()) {
|
|
|
|
if (aExtraState)
|
|
|
|
*aExtraState = nsIAccessibleStates::EXT_STATE_DEFUNCT;
|
|
|
|
|
|
|
|
return NS_OK_DEFUNCT_OBJECT;
|
|
|
|
}
|
|
|
|
|
2010-11-06 04:11:08 +00:00
|
|
|
if (aExtraState) {
|
|
|
|
// The root content of the document might be removed so that mContent is
|
|
|
|
// out of date.
|
|
|
|
*aExtraState = (mContent->GetCurrentDoc() == mDocument) ?
|
|
|
|
0 : nsIAccessibleStates::EXT_STATE_STALE;
|
|
|
|
}
|
2007-04-02 15:56:24 +00:00
|
|
|
|
2007-07-24 07:50:51 +00:00
|
|
|
#ifdef MOZ_XUL
|
2007-04-09 13:40:25 +00:00
|
|
|
nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
|
2007-07-24 07:50:51 +00:00
|
|
|
if (!xulDoc)
|
|
|
|
#endif
|
|
|
|
{
|
2007-04-09 13:40:25 +00:00
|
|
|
// XXX Need to invent better check to see if doc is focusable,
|
|
|
|
// which it should be if it is scrollable. A XUL document could be focusable.
|
|
|
|
// See bug 376803.
|
|
|
|
*aState |= nsIAccessibleStates::STATE_FOCUSABLE;
|
2010-06-11 08:23:18 +00:00
|
|
|
if (gLastFocusedNode == mDocument)
|
2008-05-04 17:42:19 +00:00
|
|
|
*aState |= nsIAccessibleStates::STATE_FOCUSED;
|
2007-04-09 13:40:25 +00:00
|
|
|
}
|
2006-04-10 14:25:14 +00:00
|
|
|
|
2010-06-08 16:39:58 +00:00
|
|
|
if (nsCoreUtils::IsDocumentBusy(mDocument)) {
|
2007-03-15 14:18:33 +00:00
|
|
|
*aState |= nsIAccessibleStates::STATE_BUSY;
|
2007-05-04 15:15:00 +00:00
|
|
|
if (aExtraState) {
|
|
|
|
*aExtraState |= nsIAccessibleStates::EXT_STATE_STALE;
|
|
|
|
}
|
2005-04-15 21:22:25 +00:00
|
|
|
}
|
2007-03-19 06:45:35 +00:00
|
|
|
|
|
|
|
nsIFrame* frame = GetFrame();
|
|
|
|
while (frame != nsnull && !frame->HasView()) {
|
|
|
|
frame = frame->GetParent();
|
2004-05-26 12:31:43 +00:00
|
|
|
}
|
2007-03-19 06:45:35 +00:00
|
|
|
|
2008-02-08 13:59:46 +00:00
|
|
|
if (frame == nsnull ||
|
|
|
|
!CheckVisibilityInParentChain(mDocument, frame->GetViewExternal())) {
|
|
|
|
*aState |= nsIAccessibleStates::STATE_INVISIBLE |
|
|
|
|
nsIAccessibleStates::STATE_OFFSCREEN;
|
2004-05-26 12:31:43 +00:00
|
|
|
}
|
2003-05-15 08:37:38 +00:00
|
|
|
|
2007-08-14 16:25:24 +00:00
|
|
|
nsCOMPtr<nsIEditor> editor;
|
|
|
|
GetAssociatedEditor(getter_AddRefs(editor));
|
2006-06-26 14:54:25 +00:00
|
|
|
if (!editor) {
|
2007-03-15 14:18:33 +00:00
|
|
|
*aState |= nsIAccessibleStates::STATE_READONLY;
|
2003-05-15 08:37:38 +00:00
|
|
|
}
|
2007-04-13 11:38:43 +00:00
|
|
|
else if (aExtraState) {
|
|
|
|
*aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
|
|
|
|
}
|
2006-06-21 13:29:10 +00:00
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
return NS_OK;
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsAccessible public method
|
2009-06-18 07:37:38 +00:00
|
|
|
nsresult
|
2009-06-25 02:12:38 +00:00
|
|
|
nsDocAccessible::GetARIAState(PRUint32 *aState, PRUint32 *aExtraState)
|
2008-03-14 20:49:38 +00:00
|
|
|
{
|
|
|
|
// Combine with states from outer doc
|
|
|
|
NS_ENSURE_ARG_POINTER(aState);
|
2009-06-25 02:12:38 +00:00
|
|
|
nsresult rv = nsAccessible::GetARIAState(aState, aExtraState);
|
2008-03-14 20:49:38 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2010-01-11 14:14:06 +00:00
|
|
|
if (mParent) // Allow iframe/frame etc. to have final state override via ARIA
|
|
|
|
return mParent->GetARIAState(aState, aExtraState);
|
2008-03-14 20:49:38 +00:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
|
|
|
|
{
|
|
|
|
nsAccessible::GetAttributes(aAttributes);
|
|
|
|
if (mParent) {
|
|
|
|
mParent->GetAttributes(aAttributes); // Add parent attributes (override inner)
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-04-10 14:25:14 +00:00
|
|
|
NS_IMETHODIMP nsDocAccessible::GetFocusedChild(nsIAccessible **aFocusedChild)
|
2005-02-18 14:36:28 +00:00
|
|
|
{
|
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 18:00:39 +00:00
|
|
|
// XXXndeakin P3 accessibility shouldn't be caching the focus
|
2005-02-18 14:36:28 +00:00
|
|
|
if (!gLastFocusedNode) {
|
|
|
|
*aFocusedChild = nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-09-09 02:30:16 +00:00
|
|
|
// Return an accessible for the current global focus, which does not have to
|
|
|
|
// be contained within the current document.
|
2010-06-11 08:23:18 +00:00
|
|
|
NS_IF_ADDREF(*aFocusedChild = GetAccService()->GetAccessible(gLastFocusedNode));
|
|
|
|
return NS_OK;
|
2005-02-18 14:36:28 +00:00
|
|
|
}
|
|
|
|
|
2007-01-10 06:32:15 +00:00
|
|
|
NS_IMETHODIMP nsDocAccessible::TakeFocus()
|
|
|
|
{
|
2010-06-11 08:23:18 +00:00
|
|
|
if (IsDefunct())
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-04-27 15:15:19 +00:00
|
|
|
PRUint32 state;
|
2008-11-04 03:37:46 +00:00
|
|
|
GetStateInternal(&state, nsnull);
|
2007-04-27 15:15:19 +00:00
|
|
|
if (0 == (state & nsIAccessibleStates::STATE_FOCUSABLE)) {
|
|
|
|
return NS_ERROR_FAILURE; // Not focusable
|
2007-01-10 06:32:15 +00:00
|
|
|
}
|
2007-04-27 15:15:19 +00:00
|
|
|
|
2010-06-11 08:23:18 +00:00
|
|
|
// Focus the document.
|
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 18:00:39 +00:00
|
|
|
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
2010-06-11 08:23:18 +00:00
|
|
|
NS_ENSURE_STATE(fm);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> newFocus;
|
|
|
|
return fm->MoveFocus(mDocument->GetWindow(), nsnull,
|
|
|
|
nsIFocusManager::MOVEFOCUS_ROOT, 0,
|
|
|
|
getter_AddRefs(newFocus));
|
2007-01-10 06:32:15 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIAccessibleDocument
|
2003-04-01 22:18:29 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP nsDocAccessible::GetURL(nsAString& aURL)
|
2006-04-10 14:25:14 +00:00
|
|
|
{
|
2010-06-11 08:23:18 +00:00
|
|
|
if (IsDefunct())
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2003-10-22 06:09:48 +00:00
|
|
|
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
|
2003-04-01 22:18:29 +00:00
|
|
|
nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(container));
|
|
|
|
nsCAutoString theURL;
|
|
|
|
if (webNav) {
|
|
|
|
nsCOMPtr<nsIURI> pURI;
|
|
|
|
webNav->GetCurrentURI(getter_AddRefs(pURI));
|
2006-04-10 14:25:14 +00:00
|
|
|
if (pURI)
|
2003-04-01 22:18:29 +00:00
|
|
|
pURI->GetSpec(theURL);
|
|
|
|
}
|
2003-12-23 16:48:40 +00:00
|
|
|
CopyUTF8toUTF16(theURL, aURL);
|
2003-04-01 22:18:29 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsDocAccessible::GetTitle(nsAString& aTitle)
|
|
|
|
{
|
2008-08-18 02:10:28 +00:00
|
|
|
nsCOMPtr<nsIDOMNSDocument> domnsDocument(do_QueryInterface(mDocument));
|
|
|
|
if (domnsDocument) {
|
|
|
|
return domnsDocument->GetTitle(aTitle);
|
2003-10-22 06:09:48 +00:00
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsDocAccessible::GetMimeType(nsAString& aMimeType)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNSDocument> domnsDocument(do_QueryInterface(mDocument));
|
|
|
|
if (domnsDocument) {
|
|
|
|
return domnsDocument->GetContentType(aMimeType);
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsDocAccessible::GetDocType(nsAString& aDocType)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mDocument));
|
|
|
|
nsCOMPtr<nsIDOMDocumentType> docType;
|
|
|
|
|
2003-04-11 00:56:27 +00:00
|
|
|
#ifdef MOZ_XUL
|
|
|
|
nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocument));
|
2003-04-01 22:18:29 +00:00
|
|
|
if (xulDoc) {
|
2004-06-17 00:13:25 +00:00
|
|
|
aDocType.AssignLiteral("window"); // doctype not implemented for XUL at time of writing - causes assertion
|
2003-04-01 22:18:29 +00:00
|
|
|
return NS_OK;
|
2003-04-11 00:56:27 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
if (domDoc && NS_SUCCEEDED(domDoc->GetDoctype(getter_AddRefs(docType))) && docType) {
|
2005-06-24 19:16:45 +00:00
|
|
|
return docType->GetPublicId(aDocType);
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsDocAccessible::GetNameSpaceURIForID(PRInt16 aNameSpaceID, nsAString& aNameSpaceURI)
|
|
|
|
{
|
|
|
|
if (mDocument) {
|
|
|
|
nsCOMPtr<nsINameSpaceManager> nameSpaceManager =
|
|
|
|
do_GetService(NS_NAMESPACEMANAGER_CONTRACTID);
|
2006-04-10 14:25:14 +00:00
|
|
|
if (nameSpaceManager)
|
2003-04-01 22:18:29 +00:00
|
|
|
return nameSpaceManager->GetNameSpaceURI(aNameSpaceID, aNameSpaceURI);
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2003-06-16 10:35:11 +00:00
|
|
|
NS_IMETHODIMP nsDocAccessible::GetWindowHandle(void **aWindow)
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
2010-09-17 03:23:17 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aWindow);
|
|
|
|
*aWindow = GetNativeWindow();
|
2003-04-01 22:18:29 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-06-16 10:35:11 +00:00
|
|
|
NS_IMETHODIMP nsDocAccessible::GetWindow(nsIDOMWindow **aDOMWin)
|
|
|
|
{
|
|
|
|
*aDOMWin = nsnull;
|
|
|
|
if (!mDocument) {
|
|
|
|
return NS_ERROR_FAILURE; // Accessible is Shutdown()
|
|
|
|
}
|
2005-11-28 23:56:44 +00:00
|
|
|
*aDOMWin = mDocument->GetWindow();
|
2003-06-16 10:35:11 +00:00
|
|
|
|
2005-11-28 23:56:44 +00:00
|
|
|
if (!*aDOMWin)
|
2003-06-16 10:35:11 +00:00
|
|
|
return NS_ERROR_FAILURE; // No DOM Window
|
|
|
|
|
2005-11-28 23:56:44 +00:00
|
|
|
NS_ADDREF(*aDOMWin);
|
2003-06-16 10:35:11 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-04-27 03:19:49 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocAccessible::GetDOMDocument(nsIDOMDocument **aDOMDocument)
|
2003-06-16 10:35:11 +00:00
|
|
|
{
|
2010-04-27 03:19:49 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aDOMDocument);
|
|
|
|
*aDOMDocument = nsnull;
|
2003-06-16 10:35:11 +00:00
|
|
|
|
2010-04-27 03:19:49 +00:00
|
|
|
if (mDocument)
|
|
|
|
CallQueryInterface(mDocument, aDOMDocument);
|
2003-06-16 10:35:11 +00:00
|
|
|
|
2010-04-27 03:19:49 +00:00
|
|
|
return NS_OK;
|
2003-06-16 10:35:11 +00:00
|
|
|
}
|
|
|
|
|
2010-09-09 14:44:56 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocAccessible::GetParentDocument(nsIAccessibleDocument** aDocument)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aDocument);
|
|
|
|
*aDocument = nsnull;
|
|
|
|
|
|
|
|
if (!IsDefunct())
|
|
|
|
NS_IF_ADDREF(*aDocument = ParentDocument());
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocAccessible::GetChildDocumentCount(PRUint32* aCount)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aCount);
|
|
|
|
*aCount = 0;
|
|
|
|
|
|
|
|
if (!IsDefunct())
|
|
|
|
*aCount = ChildDocumentCount();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocAccessible::GetChildDocumentAt(PRUint32 aIndex,
|
|
|
|
nsIAccessibleDocument** aDocument)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aDocument);
|
|
|
|
*aDocument = nsnull;
|
|
|
|
|
|
|
|
if (IsDefunct())
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
NS_IF_ADDREF(*aDocument = GetChildDocumentAt(aIndex));
|
|
|
|
return *aDocument ? NS_OK : NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsIAccessibleHyperText method
|
2007-08-14 16:25:24 +00:00
|
|
|
NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
|
2006-06-21 13:29:10 +00:00
|
|
|
{
|
2007-08-14 16:25:24 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aEditor);
|
|
|
|
*aEditor = nsnull;
|
|
|
|
|
2010-06-11 08:23:18 +00:00
|
|
|
if (IsDefunct())
|
2008-10-08 12:50:36 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Check if document is editable (designMode="on" case). Otherwise check if
|
|
|
|
// the html:body (for HTML document case) or document element is editable.
|
2010-06-11 08:23:18 +00:00
|
|
|
if (!mDocument->HasFlag(NODE_IS_EDITABLE) &&
|
|
|
|
!mContent->HasFlag(NODE_IS_EDITABLE))
|
|
|
|
return NS_OK;
|
2003-05-15 08:37:38 +00:00
|
|
|
|
2003-10-22 06:09:48 +00:00
|
|
|
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
|
2003-05-15 08:37:38 +00:00
|
|
|
nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(container));
|
|
|
|
if (!editingSession)
|
2007-08-14 16:25:24 +00:00
|
|
|
return NS_OK; // No editing session interface
|
2003-05-15 08:37:38 +00:00
|
|
|
|
2006-07-19 01:56:54 +00:00
|
|
|
nsCOMPtr<nsIEditor> editor;
|
2007-08-14 16:25:24 +00:00
|
|
|
editingSession->GetEditorForWindow(mDocument->GetWindow(), getter_AddRefs(editor));
|
|
|
|
if (!editor) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
PRBool isEditable;
|
|
|
|
editor->GetIsDocumentEditable(&isEditable);
|
|
|
|
if (isEditable) {
|
|
|
|
NS_ADDREF(*aEditor = editor);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2003-05-15 08:37:38 +00:00
|
|
|
}
|
|
|
|
|
2010-09-09 14:44:56 +00:00
|
|
|
// nsDocAccessible public method
|
2010-06-12 04:04:35 +00:00
|
|
|
nsAccessible *
|
2010-10-21 04:16:10 +00:00
|
|
|
nsDocAccessible::GetCachedAccessible(nsINode *aNode)
|
2003-04-15 08:45:55 +00:00
|
|
|
{
|
2010-10-21 04:16:10 +00:00
|
|
|
nsAccessible* accessible = mNodeToAccessibleMap.Get(aNode);
|
2010-02-11 13:56:01 +00:00
|
|
|
|
|
|
|
// No accessible in the cache, check if the given ID is unique ID of this
|
2010-06-12 04:04:35 +00:00
|
|
|
// document accessible.
|
|
|
|
if (!accessible) {
|
2010-10-21 04:16:10 +00:00
|
|
|
if (GetNode() != aNode)
|
2010-06-12 04:04:35 +00:00
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
accessible = this;
|
2010-02-11 13:56:01 +00:00
|
|
|
}
|
|
|
|
|
2010-02-09 13:29:22 +00:00
|
|
|
#ifdef DEBUG
|
2006-08-11 17:21:56 +00:00
|
|
|
// All cached accessible nodes should be in the parent
|
|
|
|
// It will assert if not all the children were created
|
|
|
|
// when they were first cached, and no invalidation
|
|
|
|
// ever corrected parent accessible's child cache.
|
2010-06-12 04:04:35 +00:00
|
|
|
nsAccessible* parent(accessible->GetCachedParent());
|
|
|
|
if (parent)
|
|
|
|
parent->TestChildCache(accessible);
|
2006-08-11 17:21:56 +00:00
|
|
|
#endif
|
2010-02-11 13:58:35 +00:00
|
|
|
|
2010-06-12 04:04:35 +00:00
|
|
|
return accessible;
|
2003-04-15 08:45:55 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsAccessNode
|
2005-08-10 01:39:43 +00:00
|
|
|
|
2010-06-12 04:04:35 +00:00
|
|
|
PRBool
|
2008-11-01 03:58:07 +00:00
|
|
|
nsDocAccessible::Init()
|
2005-08-10 01:39:43 +00:00
|
|
|
{
|
2010-06-18 02:44:09 +00:00
|
|
|
NS_LOG_ACCDOCCREATE_FOR("document initialize", mDocument, this)
|
|
|
|
|
2010-01-27 11:42:08 +00:00
|
|
|
// Initialize event queue.
|
|
|
|
mEventQueue = new nsAccEventQueue(this);
|
2010-02-21 00:56:35 +00:00
|
|
|
if (!mEventQueue)
|
2010-06-12 04:04:35 +00:00
|
|
|
return PR_FALSE;
|
2010-02-21 00:56:35 +00:00
|
|
|
|
|
|
|
AddEventListeners();
|
|
|
|
|
2010-09-09 14:44:56 +00:00
|
|
|
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
|
|
|
|
if (parentDocument)
|
|
|
|
parentDocument->AppendChildDocument(this);
|
|
|
|
|
2009-07-18 03:09:16 +00:00
|
|
|
// Fire reorder event to notify new accessible document has been created and
|
|
|
|
// attached to the tree.
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> reorderEvent =
|
2010-10-21 04:16:10 +00:00
|
|
|
new AccEvent(nsIAccessibleEvent::EVENT_REORDER, mParent, eAutoDetect,
|
|
|
|
AccEvent::eCoalesceFromSameSubtree);
|
|
|
|
if (reorderEvent) {
|
|
|
|
FireDelayedAccessibleEvent(reorderEvent);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2009-07-18 03:09:16 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
return PR_FALSE;
|
2006-04-10 14:25:14 +00:00
|
|
|
}
|
2003-05-15 08:37:38 +00:00
|
|
|
|
2010-06-12 04:04:35 +00:00
|
|
|
void
|
2008-11-01 03:58:07 +00:00
|
|
|
nsDocAccessible::Shutdown()
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
2010-06-12 04:04:35 +00:00
|
|
|
if (!mWeakShell) // already shutdown
|
|
|
|
return;
|
2003-04-15 08:45:55 +00:00
|
|
|
|
2010-06-08 16:39:58 +00:00
|
|
|
NS_LOG_ACCDOCDESTROY_FOR("document shutdown", mDocument, this)
|
|
|
|
|
2010-02-26 19:02:39 +00:00
|
|
|
if (mEventQueue) {
|
|
|
|
mEventQueue->Shutdown();
|
|
|
|
mEventQueue = nsnull;
|
|
|
|
}
|
2010-01-27 11:42:08 +00:00
|
|
|
|
2003-05-15 08:37:38 +00:00
|
|
|
RemoveEventListeners();
|
|
|
|
|
2010-09-09 14:44:56 +00:00
|
|
|
if (mParent) {
|
|
|
|
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
|
|
|
|
if (parentDocument)
|
|
|
|
parentDocument->RemoveChildDocument(this);
|
|
|
|
|
2010-06-08 16:39:58 +00:00
|
|
|
mParent->RemoveChild(this);
|
2010-09-09 14:44:56 +00:00
|
|
|
}
|
|
|
|
|
2010-11-09 19:34:25 +00:00
|
|
|
// Walk the array backwards because child documents remove themselves from the
|
|
|
|
// array as they are shutdown.
|
|
|
|
PRInt32 childDocCount = mChildDocuments.Length();
|
|
|
|
for (PRInt32 idx = childDocCount - 1; idx >= 0; idx--)
|
2010-10-28 09:34:26 +00:00
|
|
|
mChildDocuments[idx]->Shutdown();
|
|
|
|
|
2010-09-09 14:44:56 +00:00
|
|
|
mChildDocuments.Clear();
|
2010-06-08 16:39:58 +00:00
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
mWeakShell = nsnull; // Avoid reentrancy
|
|
|
|
|
2010-11-18 02:55:44 +00:00
|
|
|
mDependentIDsHash.Clear();
|
2010-10-21 04:16:10 +00:00
|
|
|
mNodeToAccessibleMap.Clear();
|
2010-06-12 04:04:35 +00:00
|
|
|
ClearCache(mAccessibleCache);
|
2007-12-27 05:13:40 +00:00
|
|
|
|
2008-02-26 08:51:10 +00:00
|
|
|
nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
|
2007-12-27 05:13:40 +00:00
|
|
|
mDocument = nsnull;
|
|
|
|
|
|
|
|
nsHyperTextAccessibleWrap::Shutdown();
|
2010-10-28 09:34:26 +00:00
|
|
|
|
|
|
|
GetAccService()->NotifyOfDocumentShutdown(kungFuDeathGripDoc);
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
2008-11-01 03:58:07 +00:00
|
|
|
nsIFrame*
|
|
|
|
nsDocAccessible::GetFrame()
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
2003-04-15 08:45:55 +00:00
|
|
|
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
|
2003-04-01 22:18:29 +00:00
|
|
|
|
|
|
|
nsIFrame* root = nsnull;
|
2006-04-10 14:25:14 +00:00
|
|
|
if (shell)
|
2004-09-02 03:08:51 +00:00
|
|
|
root = shell->GetRootFrame();
|
2003-04-01 22:18:29 +00:00
|
|
|
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
2009-06-25 02:08:53 +00:00
|
|
|
PRBool
|
|
|
|
nsDocAccessible::IsDefunct()
|
|
|
|
{
|
2010-06-11 08:23:18 +00:00
|
|
|
return nsHyperTextAccessibleWrap::IsDefunct() || !mDocument;
|
2009-06-25 02:08:53 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible protected member
|
2003-07-31 08:09:39 +00:00
|
|
|
void nsDocAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aRelativeFrame)
|
2003-04-01 22:18:29 +00:00
|
|
|
{
|
|
|
|
*aRelativeFrame = GetFrame();
|
2003-05-19 09:07:41 +00:00
|
|
|
|
2003-10-22 06:09:48 +00:00
|
|
|
nsIDocument *document = mDocument;
|
|
|
|
nsIDocument *parentDoc = nsnull;
|
2003-05-19 09:07:41 +00:00
|
|
|
|
|
|
|
while (document) {
|
2010-06-25 13:59:57 +00:00
|
|
|
nsIPresShell *presShell = document->GetShell();
|
2003-05-19 09:07:41 +00:00
|
|
|
if (!presShell) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-03 03:57:41 +00:00
|
|
|
nsRect scrollPort;
|
|
|
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollableExternal();
|
|
|
|
if (sf) {
|
|
|
|
scrollPort = sf->GetScrollPortRect();
|
|
|
|
} else {
|
2010-01-21 01:07:35 +00:00
|
|
|
nsIFrame* rootFrame = presShell->GetRootFrame();
|
|
|
|
if (!rootFrame) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
scrollPort = rootFrame->GetRect();
|
2003-05-19 09:07:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (parentDoc) { // After first time thru loop
|
2009-09-03 03:57:41 +00:00
|
|
|
// XXXroc bogus code! scrollPort is relative to the viewport of
|
|
|
|
// this document, but we're intersecting rectangles derived from
|
|
|
|
// multiple documents and assuming they're all in the same coordinate
|
|
|
|
// system. See bug 514117.
|
|
|
|
aBounds.IntersectRect(scrollPort, aBounds);
|
2003-05-19 09:07:41 +00:00
|
|
|
}
|
|
|
|
else { // First time through loop
|
2009-09-03 03:57:41 +00:00
|
|
|
aBounds = scrollPort;
|
2003-05-19 09:07:41 +00:00
|
|
|
}
|
|
|
|
|
2003-10-22 06:09:48 +00:00
|
|
|
document = parentDoc = document->GetParentDocument();
|
2003-05-19 09:07:41 +00:00
|
|
|
}
|
2003-04-01 22:18:29 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible protected member
|
2003-07-22 14:55:22 +00:00
|
|
|
nsresult nsDocAccessible::AddEventListeners()
|
2003-04-15 08:45:55 +00:00
|
|
|
{
|
|
|
|
// 1) Set up scroll position listener
|
2005-08-30 22:37:16 +00:00
|
|
|
// 2) Check for editor and listen for changes to editor
|
2003-04-15 08:45:55 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> presShell(GetPresShell());
|
2003-07-22 14:55:22 +00:00
|
|
|
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
2003-04-15 08:45:55 +00:00
|
|
|
|
2003-10-22 06:09:48 +00:00
|
|
|
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
|
2003-04-15 08:45:55 +00:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
|
2003-07-22 14:55:22 +00:00
|
|
|
NS_ENSURE_TRUE(docShellTreeItem, NS_ERROR_FAILURE);
|
2003-04-15 08:45:55 +00:00
|
|
|
|
|
|
|
// Make sure we're a content docshell
|
|
|
|
// We don't want to listen to chrome progress
|
|
|
|
PRInt32 itemType;
|
|
|
|
docShellTreeItem->GetItemType(&itemType);
|
|
|
|
|
2003-06-26 08:45:39 +00:00
|
|
|
PRBool isContent = (itemType == nsIDocShellTreeItem::typeContent);
|
2003-04-15 08:45:55 +00:00
|
|
|
|
2003-06-26 08:45:39 +00:00
|
|
|
if (isContent) {
|
2007-08-14 16:25:24 +00:00
|
|
|
// We're not an editor yet, but we might become one
|
|
|
|
nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
|
|
|
|
if (commandManager) {
|
|
|
|
commandManager->AddCommandObserver(this, "obs_documentCreated");
|
2003-05-15 08:37:38 +00:00
|
|
|
}
|
2005-03-14 16:31:43 +00:00
|
|
|
}
|
2003-04-15 08:45:55 +00:00
|
|
|
|
2007-05-07 18:55:17 +00:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
|
|
|
|
docShellTreeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
|
|
|
|
if (rootTreeItem) {
|
2010-06-08 16:39:58 +00:00
|
|
|
nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible();
|
2007-06-14 17:12:50 +00:00
|
|
|
NS_ENSURE_TRUE(rootAccessible, NS_ERROR_FAILURE);
|
|
|
|
nsRefPtr<nsCaretAccessible> caretAccessible = rootAccessible->GetCaretAccessible();
|
|
|
|
if (caretAccessible) {
|
2008-01-29 04:38:18 +00:00
|
|
|
caretAccessible->AddDocSelectionListener(presShell);
|
2007-05-07 18:55:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-10 13:57:27 +00:00
|
|
|
// add document observer
|
|
|
|
mDocument->AddObserver(this);
|
|
|
|
return NS_OK;
|
2003-04-15 08:45:55 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible protected member
|
2003-07-22 14:55:22 +00:00
|
|
|
nsresult nsDocAccessible::RemoveEventListeners()
|
2003-04-15 08:45:55 +00:00
|
|
|
{
|
|
|
|
// Remove listeners associated with content documents
|
|
|
|
// Remove scroll position listener
|
2004-11-08 02:29:47 +00:00
|
|
|
RemoveScrollListener();
|
2003-04-28 10:24:52 +00:00
|
|
|
|
2009-06-28 17:45:04 +00:00
|
|
|
NS_ASSERTION(mDocument, "No document during removal of listeners.");
|
|
|
|
|
|
|
|
if (mDocument) {
|
|
|
|
mDocument->RemoveObserver(this);
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
|
|
|
|
NS_ASSERTION(docShellTreeItem, "doc should support nsIDocShellTreeItem.");
|
|
|
|
|
|
|
|
if (docShellTreeItem) {
|
|
|
|
PRInt32 itemType;
|
|
|
|
docShellTreeItem->GetItemType(&itemType);
|
|
|
|
if (itemType == nsIDocShellTreeItem::typeContent) {
|
|
|
|
nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
|
|
|
|
if (commandManager) {
|
|
|
|
commandManager->RemoveCommandObserver(this, "obs_documentCreated");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-05-15 08:37:38 +00:00
|
|
|
|
2003-06-16 10:22:40 +00:00
|
|
|
if (mScrollWatchTimer) {
|
|
|
|
mScrollWatchTimer->Cancel();
|
|
|
|
mScrollWatchTimer = nsnull;
|
2008-01-18 20:36:44 +00:00
|
|
|
NS_RELEASE_THIS(); // Kung fu death grip
|
2003-06-16 10:22:40 +00:00
|
|
|
}
|
|
|
|
|
2007-05-07 18:55:17 +00:00
|
|
|
nsRefPtr<nsRootAccessible> rootAccessible(GetRootAccessible());
|
|
|
|
if (rootAccessible) {
|
2007-06-14 17:12:50 +00:00
|
|
|
nsRefPtr<nsCaretAccessible> caretAccessible = rootAccessible->GetCaretAccessible();
|
|
|
|
if (caretAccessible) {
|
2008-01-30 05:42:44 +00:00
|
|
|
// Don't use GetPresShell() which can call Shutdown() if it sees dead pres shell
|
|
|
|
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
|
2008-01-29 04:38:18 +00:00
|
|
|
caretAccessible->RemoveDocSelectionListener(presShell);
|
2007-05-07 18:55:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-07-22 14:55:22 +00:00
|
|
|
return NS_OK;
|
2003-04-15 08:45:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void nsDocAccessible::ScrollTimerCallback(nsITimer *aTimer, void *aClosure)
|
|
|
|
{
|
2007-07-08 07:08:04 +00:00
|
|
|
nsDocAccessible *docAcc = reinterpret_cast<nsDocAccessible*>(aClosure);
|
2003-04-15 08:45:55 +00:00
|
|
|
|
2006-04-10 14:25:14 +00:00
|
|
|
if (docAcc && docAcc->mScrollPositionChangedTicks &&
|
2003-04-15 08:45:55 +00:00
|
|
|
++docAcc->mScrollPositionChangedTicks > 2) {
|
|
|
|
// Whenever scroll position changes, mScrollPositionChangeTicks gets reset to 1
|
|
|
|
// We only want to fire accessibilty scroll event when scrolling stops or pauses
|
|
|
|
// Therefore, we wait for no scroll events to occur between 2 ticks of this timer
|
|
|
|
// That indicates a pause in scrolling, so we fire the accessibilty scroll event
|
2010-01-18 16:16:07 +00:00
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SCROLLING_END, docAcc);
|
2007-07-05 16:02:55 +00:00
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
docAcc->mScrollPositionChangedTicks = 0;
|
2003-05-01 10:25:45 +00:00
|
|
|
if (docAcc->mScrollWatchTimer) {
|
|
|
|
docAcc->mScrollWatchTimer->Cancel();
|
|
|
|
docAcc->mScrollWatchTimer = nsnull;
|
2008-01-18 20:36:44 +00:00
|
|
|
NS_RELEASE(docAcc); // Release kung fu death grip
|
2003-05-01 10:25:45 +00:00
|
|
|
}
|
2003-04-15 08:45:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible protected member
|
2004-11-08 02:29:47 +00:00
|
|
|
void nsDocAccessible::AddScrollListener()
|
2003-04-15 08:45:55 +00:00
|
|
|
{
|
2004-11-08 02:29:47 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
|
2009-09-03 03:57:41 +00:00
|
|
|
if (!presShell)
|
|
|
|
return;
|
2004-11-08 02:29:47 +00:00
|
|
|
|
2009-09-03 03:57:41 +00:00
|
|
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollableExternal();
|
|
|
|
if (sf) {
|
|
|
|
sf->AddScrollPositionListener(this);
|
2010-06-08 16:39:58 +00:00
|
|
|
NS_LOG_ACCDOCCREATE_TEXT("add scroll listener")
|
2009-09-03 03:57:41 +00:00
|
|
|
}
|
2003-04-15 08:45:55 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible protected member
|
2004-11-08 02:29:47 +00:00
|
|
|
void nsDocAccessible::RemoveScrollListener()
|
2003-04-15 08:45:55 +00:00
|
|
|
{
|
2004-11-08 02:29:47 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
|
2009-09-03 03:57:41 +00:00
|
|
|
if (!presShell)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollableExternal();
|
|
|
|
if (sf) {
|
|
|
|
sf->RemoveScrollPositionListener(this);
|
|
|
|
}
|
2003-04-15 08:45:55 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIScrollPositionListener
|
|
|
|
|
2010-01-29 00:03:42 +00:00
|
|
|
void nsDocAccessible::ScrollPositionDidChange(nscoord aX, nscoord aY)
|
2003-04-15 08:45:55 +00:00
|
|
|
{
|
2006-04-10 14:25:14 +00:00
|
|
|
// Start new timer, if the timer cycles at least 1 full cycle without more scroll position changes,
|
2003-04-15 08:45:55 +00:00
|
|
|
// then the ::Notify() method will fire the accessibility event for scroll position changes
|
|
|
|
const PRUint32 kScrollPosCheckWait = 50;
|
|
|
|
if (mScrollWatchTimer) {
|
|
|
|
mScrollWatchTimer->SetDelay(kScrollPosCheckWait); // Create new timer, to avoid leaks
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mScrollWatchTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
|
|
if (mScrollWatchTimer) {
|
2008-01-18 20:36:44 +00:00
|
|
|
NS_ADDREF_THIS(); // Kung fu death grip
|
2003-04-15 08:45:55 +00:00
|
|
|
mScrollWatchTimer->InitWithFuncCallback(ScrollTimerCallback, this,
|
2006-04-10 14:25:14 +00:00
|
|
|
kScrollPosCheckWait,
|
2003-04-15 08:45:55 +00:00
|
|
|
nsITimer::TYPE_REPEATING_SLACK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mScrollPositionChangedTicks = 1;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIObserver
|
|
|
|
|
2003-05-15 08:37:38 +00:00
|
|
|
NS_IMETHODIMP nsDocAccessible::Observe(nsISupports *aSubject, const char *aTopic,
|
|
|
|
const PRUnichar *aData)
|
|
|
|
{
|
2007-08-14 16:25:24 +00:00
|
|
|
if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {
|
|
|
|
// State editable will now be set, readonly is now clear
|
2010-06-02 12:30:08 +00:00
|
|
|
// Normally we only fire delayed events created from the node, not an
|
2010-08-25 02:08:28 +00:00
|
|
|
// accessible object. See the AccStateChangeEvent constructor for details
|
2010-06-02 12:30:08 +00:00
|
|
|
// about this exceptional case.
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
|
|
|
|
PR_TRUE, PR_TRUE);
|
2010-06-02 12:30:08 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
2003-05-15 08:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2005-06-10 13:57:27 +00:00
|
|
|
// nsIDocumentObserver
|
2003-04-28 10:24:52 +00:00
|
|
|
|
2005-06-10 13:57:27 +00:00
|
|
|
NS_IMPL_NSIDOCUMENTOBSERVER_CORE_STUB(nsDocAccessible)
|
|
|
|
NS_IMPL_NSIDOCUMENTOBSERVER_LOAD_STUB(nsDocAccessible)
|
|
|
|
NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(nsDocAccessible)
|
2003-04-28 10:24:52 +00:00
|
|
|
|
2009-06-29 18:36:25 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::AttributeWillChange(nsIDocument *aDocument,
|
2010-08-24 07:06:20 +00:00
|
|
|
dom::Element* aElement,
|
|
|
|
PRInt32 aNameSpaceID,
|
2009-06-29 18:36:25 +00:00
|
|
|
nsIAtom* aAttribute, PRInt32 aModType)
|
|
|
|
{
|
2010-11-18 02:55:44 +00:00
|
|
|
// XXX TODO: bugs 381599 (partially fixed by 573469), 467143, 472142, 472143.
|
2009-06-29 18:36:25 +00:00
|
|
|
// Here we will want to cache whatever state we are potentially interested in,
|
|
|
|
// such as the existence of aria-pressed for button (so we know if we need to
|
|
|
|
// newly expose it as a toggle button) etc.
|
2010-11-18 02:55:44 +00:00
|
|
|
|
|
|
|
// Update dependent IDs cache.
|
|
|
|
if (aModType == nsIDOMMutationEvent::MODIFICATION ||
|
|
|
|
aModType == nsIDOMMutationEvent::REMOVAL) {
|
|
|
|
nsAccessible* accessible =
|
|
|
|
GetAccService()->GetAccessibleInWeakShell(aElement, mWeakShell);
|
|
|
|
if (accessible)
|
|
|
|
RemoveDependentIDsFor(accessible, aAttribute);
|
|
|
|
}
|
2009-06-29 18:36:25 +00:00
|
|
|
}
|
|
|
|
|
2005-06-10 13:57:27 +00:00
|
|
|
void
|
2010-08-24 07:05:56 +00:00
|
|
|
nsDocAccessible::AttributeChanged(nsIDocument *aDocument,
|
|
|
|
dom::Element* aElement,
|
2005-06-10 13:57:27 +00:00
|
|
|
PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
2009-12-10 22:36:04 +00:00
|
|
|
PRInt32 aModType)
|
2007-09-18 21:36:41 +00:00
|
|
|
{
|
2010-08-24 07:05:56 +00:00
|
|
|
AttributeChangedImpl(aElement, aNameSpaceID, aAttribute);
|
2007-09-18 21:36:41 +00:00
|
|
|
|
2010-11-18 02:55:44 +00:00
|
|
|
// Update dependent IDs cache.
|
|
|
|
if (aModType == nsIDOMMutationEvent::MODIFICATION ||
|
|
|
|
aModType == nsIDOMMutationEvent::ADDITION) {
|
|
|
|
nsAccessible* accessible =
|
|
|
|
GetAccService()->GetAccessibleInWeakShell(aElement, mWeakShell);
|
|
|
|
|
|
|
|
if (accessible)
|
|
|
|
AddDependentIDsFor(accessible, aAttribute);
|
|
|
|
}
|
|
|
|
|
2007-09-18 21:36:41 +00:00
|
|
|
// If it was the focused node, cache the new state
|
2010-08-24 07:05:56 +00:00
|
|
|
if (aElement == gLastFocusedNode) {
|
|
|
|
nsAccessible *focusedAccessible = GetAccService()->GetAccessible(aElement);
|
2010-06-11 08:23:18 +00:00
|
|
|
if (focusedAccessible)
|
2008-10-17 10:10:43 +00:00
|
|
|
gLastFocusedAccessiblesState = nsAccUtils::State(focusedAccessible);
|
2007-09-18 21:36:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible protected member
|
2007-09-18 21:36:41 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aAttribute)
|
2003-04-28 10:24:52 +00:00
|
|
|
{
|
2007-04-17 04:45:42 +00:00
|
|
|
// Fire accessible event after short timer, because we need to wait for
|
|
|
|
// DOM attribute & resulting layout to actually change. Otherwise,
|
|
|
|
// assistive technology will retrieve the wrong state/value/selection info.
|
|
|
|
|
2003-04-28 10:24:52 +00:00
|
|
|
// XXX todo
|
2005-01-28 02:35:26 +00:00
|
|
|
// We still need to handle special HTML cases here
|
2003-04-28 10:24:52 +00:00
|
|
|
// For example, if an <img>'s usemap attribute is modified
|
|
|
|
// Otherwise it may just be a state change, for example an object changing
|
2005-01-28 02:35:26 +00:00
|
|
|
// its visibility
|
2009-01-12 17:20:34 +00:00
|
|
|
//
|
|
|
|
// XXX todo: report aria state changes for "undefined" literal value changes
|
|
|
|
// filed as bug 472142
|
|
|
|
//
|
|
|
|
// XXX todo: invalidate accessible when aria state changes affect exposed role
|
|
|
|
// filed as bug 472143
|
|
|
|
|
2005-06-10 13:57:27 +00:00
|
|
|
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
|
|
|
|
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
|
|
|
|
if (!docShell) {
|
|
|
|
return;
|
|
|
|
}
|
2007-09-25 01:19:03 +00:00
|
|
|
|
2010-06-08 16:39:58 +00:00
|
|
|
if (!IsContentLoaded())
|
2005-06-10 13:57:27 +00:00
|
|
|
return; // Still loading, ignore setting of initial attributes
|
|
|
|
|
2005-01-28 02:35:26 +00:00
|
|
|
nsCOMPtr<nsIPresShell> shell = GetPresShell();
|
|
|
|
if (!shell) {
|
2005-06-10 13:57:27 +00:00
|
|
|
return; // Document has been shut down
|
2005-01-28 02:35:26 +00:00
|
|
|
}
|
|
|
|
|
2010-06-11 08:23:18 +00:00
|
|
|
NS_ASSERTION(aContent, "No node for attr modified");
|
2007-04-19 13:16:23 +00:00
|
|
|
|
2009-09-16 01:01:47 +00:00
|
|
|
// Universal boolean properties that don't require a role. Fire the state
|
|
|
|
// change when disabled or aria-disabled attribute is set.
|
2007-09-25 01:19:03 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::disabled ||
|
2007-12-12 02:10:26 +00:00
|
|
|
aAttribute == nsAccessibilityAtoms::aria_disabled) {
|
2009-09-16 01:01:47 +00:00
|
|
|
|
|
|
|
// Note. Checking the XUL or HTML namespace would not seem to gain us
|
|
|
|
// anything, because disabled attribute really is going to mean the same
|
|
|
|
// thing in any namespace.
|
|
|
|
|
|
|
|
// Note. We use the attribute instead of the disabled state bit because
|
|
|
|
// ARIA's aria-disabled does not affect the disabled state bit.
|
|
|
|
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> enabledChangeEvent =
|
|
|
|
new AccStateChangeEvent(aContent,
|
|
|
|
nsIAccessibleStates::EXT_STATE_ENABLED,
|
|
|
|
PR_TRUE);
|
2009-09-16 01:01:47 +00:00
|
|
|
|
2007-04-19 17:49:13 +00:00
|
|
|
FireDelayedAccessibleEvent(enabledChangeEvent);
|
2009-09-16 01:01:47 +00:00
|
|
|
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> sensitiveChangeEvent =
|
|
|
|
new AccStateChangeEvent(aContent,
|
|
|
|
nsIAccessibleStates::EXT_STATE_SENSITIVE,
|
|
|
|
PR_TRUE);
|
2009-09-16 01:01:47 +00:00
|
|
|
|
2007-04-19 17:49:13 +00:00
|
|
|
FireDelayedAccessibleEvent(sensitiveChangeEvent);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-09-25 01:19:03 +00:00
|
|
|
// Check for namespaced ARIA attribute
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
2007-09-25 01:19:03 +00:00
|
|
|
// Check for hyphenated aria-foo property?
|
2010-03-08 15:45:00 +00:00
|
|
|
if (StringBeginsWith(nsDependentAtomString(aAttribute),
|
|
|
|
NS_LITERAL_STRING("aria-"))) {
|
2007-12-12 02:10:26 +00:00
|
|
|
ARIAAttributeChanged(aContent, aAttribute);
|
2007-09-25 01:19:03 +00:00
|
|
|
}
|
|
|
|
}
|
2007-04-19 17:49:13 +00:00
|
|
|
|
2010-11-15 18:30:43 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::role) {
|
|
|
|
if (mContent == aContent) {
|
|
|
|
// It is common for js libraries to set the role of the body element after
|
|
|
|
// the doc has loaded. In this case we just update the role map entry.
|
|
|
|
SetRoleMapEntry(nsAccUtils::GetRoleMapEntry(aContent));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Recreate the accessible when role is changed because we might require a
|
|
|
|
// different accessible class for the new role or the accessible may
|
|
|
|
// expose a different sets of interfaces (COM restriction).
|
|
|
|
RecreateAccessible(aContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aAttribute == nsAccessibilityAtoms::href ||
|
2009-04-09 15:36:25 +00:00
|
|
|
aAttribute == nsAccessibilityAtoms::onclick) {
|
2007-09-28 18:16:05 +00:00
|
|
|
// Not worth the expense to ensure which namespace these are in
|
|
|
|
// It doesn't kill use to recreate the accessible even if the attribute was used
|
|
|
|
// in the wrong namespace or an element that doesn't support it
|
2010-10-21 04:16:10 +00:00
|
|
|
RecreateAccessible(aContent);
|
2005-08-10 01:51:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-02-20 07:45:14 +00:00
|
|
|
|
|
|
|
if (aAttribute == nsAccessibilityAtoms::alt ||
|
2009-05-14 05:27:40 +00:00
|
|
|
aAttribute == nsAccessibilityAtoms::title ||
|
|
|
|
aAttribute == nsAccessibilityAtoms::aria_label ||
|
|
|
|
aAttribute == nsAccessibilityAtoms::aria_labelledby) {
|
2009-09-03 02:01:18 +00:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE,
|
2010-06-11 08:23:18 +00:00
|
|
|
aContent);
|
2008-02-20 07:45:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-08-10 01:51:39 +00:00
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::selected ||
|
|
|
|
aAttribute == nsAccessibilityAtoms::aria_selected) {
|
|
|
|
// ARIA or XUL selection
|
2010-06-11 08:23:18 +00:00
|
|
|
|
|
|
|
nsAccessible *multiSelect =
|
|
|
|
nsAccUtils::GetMultiSelectableContainer(aContent);
|
2005-07-14 14:20:21 +00:00
|
|
|
// Multi selects use selection_add and selection_remove
|
|
|
|
// Single select widgets just mirror event_selection for
|
|
|
|
// whatever gets event_focus, which is done in
|
|
|
|
// nsRootAccessible::FireAccessibleFocusEvent()
|
|
|
|
// So right here we make sure only to deal with multi selects
|
|
|
|
if (multiSelect) {
|
|
|
|
// Need to find the right event to use here, SELECTION_WITHIN would
|
|
|
|
// seem right but we had started using it for something else
|
2009-09-03 02:01:18 +00:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
|
2010-06-11 08:23:18 +00:00
|
|
|
multiSelect->GetNode(),
|
2010-08-25 02:08:28 +00:00
|
|
|
AccEvent::eAllowDupes);
|
2007-04-17 04:45:42 +00:00
|
|
|
|
2006-04-24 05:40:11 +00:00
|
|
|
static nsIContent::AttrValuesArray strings[] =
|
|
|
|
{&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aContent->FindAttrValueIn(kNameSpaceID_None, aAttribute,
|
|
|
|
strings, eCaseMatters) >= 0) {
|
2009-09-03 02:01:18 +00:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_REMOVE,
|
2010-06-11 08:23:18 +00:00
|
|
|
aContent);
|
2007-04-17 04:45:42 +00:00
|
|
|
return;
|
2005-07-14 14:20:21 +00:00
|
|
|
}
|
2007-04-17 04:45:42 +00:00
|
|
|
|
2009-09-03 02:01:18 +00:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD,
|
2010-06-11 08:23:18 +00:00
|
|
|
aContent);
|
2005-07-14 14:20:21 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-14 16:25:24 +00:00
|
|
|
|
|
|
|
if (aAttribute == nsAccessibilityAtoms::contenteditable) {
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> editableChangeEvent =
|
|
|
|
new AccStateChangeEvent(aContent,
|
|
|
|
nsIAccessibleStates::EXT_STATE_EDITABLE,
|
|
|
|
PR_TRUE);
|
2007-08-14 16:25:24 +00:00
|
|
|
FireDelayedAccessibleEvent(editableChangeEvent);
|
|
|
|
return;
|
|
|
|
}
|
2007-04-17 04:45:42 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible protected member
|
2007-04-17 04:45:42 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
|
|
|
{
|
2010-04-02 13:33:55 +00:00
|
|
|
// Note: For universal/global ARIA states and properties we don't care if
|
|
|
|
// there is an ARIA role present or not.
|
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_required) {
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(aContent, nsIAccessibleStates::STATE_REQUIRED,
|
|
|
|
PR_FALSE);
|
2007-04-17 04:45:42 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_invalid) {
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(aContent, nsIAccessibleStates::STATE_INVALID,
|
|
|
|
PR_FALSE);
|
2007-04-17 04:45:42 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_activedescendant) {
|
2007-04-17 04:45:42 +00:00
|
|
|
// The activedescendant universal property redirects accessible focus events
|
|
|
|
// to the element with the id that activedescendant points to
|
2010-06-11 08:23:18 +00:00
|
|
|
nsCOMPtr<nsINode> focusedNode = GetCurrentFocus();
|
|
|
|
if (nsCoreUtils::GetRoleContent(focusedNode) == aContent) {
|
2007-04-17 04:45:42 +00:00
|
|
|
nsRefPtr<nsRootAccessible> rootAcc = GetRootAccessible();
|
2010-06-15 14:53:36 +00:00
|
|
|
if (rootAcc) {
|
2010-06-11 08:23:18 +00:00
|
|
|
rootAcc->FireAccessibleFocusEvent(nsnull, focusedNode, nsnull, PR_TRUE);
|
2010-06-15 14:53:36 +00:00
|
|
|
}
|
2005-07-14 14:20:21 +00:00
|
|
|
}
|
2007-04-17 04:45:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-04-02 13:33:55 +00:00
|
|
|
// For aria drag and drop changes we fire a generic attribute change event;
|
|
|
|
// at least until native API comes up with a more meaningful event.
|
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_grabbed ||
|
|
|
|
aAttribute == nsAccessibilityAtoms::aria_dropeffect) {
|
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
|
2010-06-11 08:23:18 +00:00
|
|
|
aContent);
|
2010-04-02 13:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We treat aria-expanded as a global ARIA state for historical reasons
|
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_expanded) {
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(aContent, nsIAccessibleStates::STATE_EXPANDED,
|
|
|
|
PR_FALSE);
|
2010-04-02 13:33:55 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
if (!aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) {
|
2007-04-17 04:45:42 +00:00
|
|
|
// We don't care about these other ARIA attribute changes unless there is
|
|
|
|
// an ARIA role set for the element
|
|
|
|
// XXX: we should check the role map to see if the changed property is
|
|
|
|
// relevant for that particular role.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
// The following ARIA attributes only take affect when dynamic content role is present
|
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_checked ||
|
|
|
|
aAttribute == nsAccessibilityAtoms::aria_pressed) {
|
|
|
|
const PRUint32 kState = (aAttribute == nsAccessibilityAtoms::aria_checked) ?
|
2007-09-18 21:36:41 +00:00
|
|
|
nsIAccessibleStates::STATE_CHECKED :
|
|
|
|
nsIAccessibleStates::STATE_PRESSED;
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(aContent, kState, PR_FALSE);
|
2007-08-14 16:15:12 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
2010-06-11 08:23:18 +00:00
|
|
|
if (aContent == gLastFocusedNode) {
|
2007-09-18 21:36:41 +00:00
|
|
|
// State changes for MIXED state currently only supported for focused item, because
|
|
|
|
// otherwise we would need access to the old attribute value in this listener.
|
2007-12-12 02:10:26 +00:00
|
|
|
// This is because we don't know if the previous value of aria-checked or aria-pressed was "mixed"
|
2007-09-18 21:36:41 +00:00
|
|
|
// without caching that info.
|
2010-06-12 04:04:24 +00:00
|
|
|
nsAccessible *accessible = event->GetAccessible();
|
2007-09-18 21:36:41 +00:00
|
|
|
if (accessible) {
|
|
|
|
PRBool wasMixed = (gLastFocusedAccessiblesState & nsIAccessibleStates::STATE_MIXED) != 0;
|
2008-10-17 10:10:43 +00:00
|
|
|
PRBool isMixed =
|
|
|
|
(nsAccUtils::State(accessible) & nsIAccessibleStates::STATE_MIXED) != 0;
|
2007-09-18 21:36:41 +00:00
|
|
|
if (wasMixed != isMixed) {
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(aContent, nsIAccessibleStates::STATE_MIXED,
|
|
|
|
PR_FALSE, isMixed);
|
2007-09-18 21:36:41 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-08-14 16:15:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_readonly) {
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(aContent, nsIAccessibleStates::STATE_READONLY,
|
|
|
|
PR_FALSE);
|
2007-04-17 04:45:42 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-06-11 19:57:29 +00:00
|
|
|
// Fire value change event whenever aria-valuetext is changed, or
|
|
|
|
// when aria-valuenow is changed and aria-valuetext is empty
|
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_valuetext ||
|
|
|
|
(aAttribute == nsAccessibilityAtoms::aria_valuenow &&
|
|
|
|
(!aContent->HasAttr(kNameSpaceID_None,
|
|
|
|
nsAccessibilityAtoms::aria_valuetext) ||
|
|
|
|
aContent->AttrValueIs(kNameSpaceID_None,
|
|
|
|
nsAccessibilityAtoms::aria_valuetext, nsAccessibilityAtoms::_empty,
|
|
|
|
eCaseMatters)))) {
|
2009-09-03 02:01:18 +00:00
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
|
2010-06-11 08:23:18 +00:00
|
|
|
aContent);
|
2007-04-17 04:45:42 +00:00
|
|
|
return;
|
2005-01-28 02:35:26 +00:00
|
|
|
}
|
|
|
|
|
2007-12-12 02:10:26 +00:00
|
|
|
if (aAttribute == nsAccessibilityAtoms::aria_multiselectable &&
|
|
|
|
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) {
|
2010-09-02 00:46:59 +00:00
|
|
|
// This affects whether the accessible supports SelectAccessible.
|
2007-04-17 04:45:42 +00:00
|
|
|
// COM says we cannot change what interfaces are supported on-the-fly,
|
|
|
|
// so invalidate this object. A new one will be created on demand.
|
2010-10-21 04:16:10 +00:00
|
|
|
RecreateAccessible(aContent);
|
2009-08-20 14:16:00 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-06-10 13:57:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
|
|
|
|
nsIContent* aContainer,
|
2010-05-11 01:12:34 +00:00
|
|
|
nsIContent* aFirstNewContent,
|
|
|
|
PRInt32 /* unused */)
|
2005-06-10 13:57:27 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-25 21:40:31 +00:00
|
|
|
void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContent1,
|
|
|
|
nsIContent* aContent2,
|
2010-10-20 11:26:32 +00:00
|
|
|
nsEventStates aStateMask)
|
2005-07-25 21:40:31 +00:00
|
|
|
{
|
2010-11-08 13:33:18 +00:00
|
|
|
if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
|
|
|
|
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent1);
|
|
|
|
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2);
|
2005-07-25 21:40:31 +00:00
|
|
|
}
|
|
|
|
|
2010-11-08 13:33:18 +00:00
|
|
|
if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) {
|
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccStateChangeEvent(aContent1, nsIAccessibleStates::STATE_INVALID,
|
|
|
|
PR_FALSE, PR_TRUE);
|
|
|
|
FireDelayedAccessibleEvent(event);
|
|
|
|
}
|
2005-07-25 21:40:31 +00:00
|
|
|
}
|
|
|
|
|
2010-03-17 17:10:57 +00:00
|
|
|
void nsDocAccessible::DocumentStatesChanged(nsIDocument* aDocument,
|
2010-10-20 11:26:32 +00:00
|
|
|
nsEventStates aStateMask)
|
2010-03-17 17:10:57 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-09-05 08:22:17 +00:00
|
|
|
void nsDocAccessible::CharacterDataWillChange(nsIDocument *aDocument,
|
|
|
|
nsIContent* aContent,
|
|
|
|
CharacterDataChangeInfo* aInfo)
|
|
|
|
{
|
|
|
|
FireTextChangeEventForText(aContent, aInfo, PR_FALSE);
|
|
|
|
}
|
|
|
|
|
2005-06-10 13:57:27 +00:00
|
|
|
void nsDocAccessible::CharacterDataChanged(nsIDocument *aDocument,
|
|
|
|
nsIContent* aContent,
|
2006-11-03 21:51:01 +00:00
|
|
|
CharacterDataChangeInfo* aInfo)
|
2005-06-10 13:57:27 +00:00
|
|
|
{
|
2007-09-05 08:22:17 +00:00
|
|
|
FireTextChangeEventForText(aContent, aInfo, PR_TRUE);
|
2005-06-10 13:57:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocAccessible::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
|
2010-05-11 01:12:34 +00:00
|
|
|
nsIContent* aChild, PRInt32 /* unused */)
|
2005-06-10 13:57:27 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocAccessible::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
|
2010-07-21 22:05:17 +00:00
|
|
|
nsIContent* aChild, PRInt32 /* unused */,
|
|
|
|
nsIContent* aPreviousSibling)
|
2005-06-10 13:57:27 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-03-10 13:49:43 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::ParentChainChanged(nsIContent *aContent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsAccessible
|
|
|
|
|
2010-06-08 16:39:58 +00:00
|
|
|
#ifdef DEBUG_ACCDOCMGR
|
|
|
|
nsresult
|
2010-08-25 02:08:28 +00:00
|
|
|
nsDocAccessible::HandleAccEvent(AccEvent* aAccEvent)
|
2010-06-08 16:39:58 +00:00
|
|
|
{
|
|
|
|
NS_LOG_ACCDOCLOAD_HANDLEEVENT(aAccEvent)
|
2009-12-10 19:12:19 +00:00
|
|
|
|
2010-06-08 16:39:58 +00:00
|
|
|
return nsHyperTextAccessible::HandleAccEvent(aAccEvent);
|
2009-12-10 19:12:19 +00:00
|
|
|
|
|
|
|
}
|
2010-06-08 16:39:58 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Public members
|
2009-12-10 19:12:19 +00:00
|
|
|
|
2010-09-17 03:23:17 +00:00
|
|
|
void*
|
|
|
|
nsDocAccessible::GetNativeWindow() const
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
|
|
|
|
nsIViewManager* vm = shell->GetViewManager();
|
|
|
|
if (vm) {
|
|
|
|
nsCOMPtr<nsIWidget> widget;
|
|
|
|
vm->GetRootWidget(getter_AddRefs(widget));
|
|
|
|
if (widget)
|
|
|
|
return widget->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2010-09-09 14:44:56 +00:00
|
|
|
nsAccessible*
|
2010-10-21 04:16:10 +00:00
|
|
|
nsDocAccessible::GetCachedAccessibleByUniqueIDInSubtree(void* aUniqueID)
|
2010-09-09 14:44:56 +00:00
|
|
|
{
|
2010-10-21 04:16:10 +00:00
|
|
|
nsAccessible* child = GetCachedAccessibleByUniqueID(aUniqueID);
|
2010-09-09 14:44:56 +00:00
|
|
|
if (child)
|
|
|
|
return child;
|
|
|
|
|
|
|
|
PRUint32 childDocCount = mChildDocuments.Length();
|
|
|
|
for (PRUint32 childDocIdx= 0; childDocIdx < childDocCount; childDocIdx++) {
|
|
|
|
nsDocAccessible* childDocument = mChildDocuments.ElementAt(childDocIdx);
|
2010-10-21 04:16:10 +00:00
|
|
|
child = childDocument->GetCachedAccessibleByUniqueIDInSubtree(aUniqueID);
|
2010-09-09 14:44:56 +00:00
|
|
|
if (child)
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
2009-12-10 19:12:19 +00:00
|
|
|
|
2010-11-12 19:00:55 +00:00
|
|
|
bool
|
|
|
|
nsDocAccessible::BindToDocument(nsAccessible* aAccessible,
|
|
|
|
nsRoleMapEntry* aRoleMapEntry)
|
|
|
|
{
|
|
|
|
if (!aAccessible)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Put into DOM node cache.
|
|
|
|
if (aAccessible->IsPrimaryForNode() &&
|
|
|
|
!mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Put into unique ID cache.
|
|
|
|
if (!mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible)) {
|
|
|
|
if (aAccessible->IsPrimaryForNode())
|
|
|
|
mNodeToAccessibleMap.Remove(aAccessible->GetNode());
|
2010-11-12 19:01:04 +00:00
|
|
|
|
2010-11-12 19:00:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the accessible.
|
|
|
|
if (!aAccessible->Init()) {
|
|
|
|
NS_ERROR("Failed to initialize an accessible!");
|
|
|
|
|
|
|
|
UnbindFromDocument(aAccessible);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
aAccessible->SetRoleMapEntry(aRoleMapEntry);
|
2010-11-18 02:55:44 +00:00
|
|
|
AddDependentIDsFor(aAccessible);
|
2010-11-12 19:00:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocAccessible::UnbindFromDocument(nsAccessible* aAccessible)
|
|
|
|
{
|
2010-11-12 19:01:04 +00:00
|
|
|
// Remove an accessible from node-to-accessible map if it exists there.
|
2010-11-12 19:00:55 +00:00
|
|
|
if (aAccessible->IsPrimaryForNode() &&
|
|
|
|
mNodeToAccessibleMap.Get(aAccessible->GetNode()) == aAccessible)
|
|
|
|
mNodeToAccessibleMap.Remove(aAccessible->GetNode());
|
|
|
|
|
2010-11-18 02:55:44 +00:00
|
|
|
RemoveDependentIDsFor(aAccessible);
|
|
|
|
|
2010-11-12 19:00:55 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
|
2010-11-12 19:01:04 +00:00
|
|
|
"Unbinding the unbound accessible!");
|
2010-11-12 19:00:55 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
void* uniqueID = aAccessible->UniqueID();
|
|
|
|
aAccessible->Shutdown();
|
|
|
|
mAccessibleCache.Remove(uniqueID);
|
|
|
|
}
|
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::UpdateTree(nsIContent* aContainerNode,
|
|
|
|
nsIContent* aStartNode,
|
|
|
|
nsIContent* aEndNode,
|
|
|
|
PRBool aIsInsert)
|
|
|
|
{
|
|
|
|
// Content change notification mostly are async, thus we can't detect whether
|
|
|
|
// these actions are from user. This information is used to fire or do not
|
|
|
|
// fire events to avoid events that are generated because of document loading.
|
|
|
|
// Since this information may be not correct then we need to fire some events
|
|
|
|
// regardless the document loading state.
|
|
|
|
|
2010-11-06 04:11:08 +00:00
|
|
|
// Update the whole tree of this document accessible when the container is
|
|
|
|
// null (document element is inserted or removed).
|
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
|
|
|
nsIEventStateManager* esm = presShell->GetPresContext()->EventStateManager();
|
|
|
|
PRBool fireAllEvents = PR_TRUE;//IsContentLoaded() || esm->IsHandlingUserInputExternal();
|
|
|
|
|
2010-11-06 04:11:08 +00:00
|
|
|
// XXX: bug 608887 reconsider accessible tree update logic because
|
|
|
|
// 1) elements appended outside the HTML body don't get accessibles;
|
|
|
|
// 2) the document having elements that should be accessible may function
|
|
|
|
// without body.
|
|
|
|
nsAccessible* container = nsnull;
|
2010-10-21 04:16:10 +00:00
|
|
|
if (aIsInsert) {
|
2010-11-06 04:11:08 +00:00
|
|
|
container = aContainerNode ?
|
|
|
|
GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
|
|
|
|
this;
|
|
|
|
|
|
|
|
// The document children were changed; the root content might be affected.
|
|
|
|
if (container == this) {
|
|
|
|
nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocument);
|
|
|
|
|
|
|
|
// No root content (for example HTML document element was inserted but no
|
|
|
|
// body). Nothing to update.
|
|
|
|
if (!rootContent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// New root content has been inserted, update it and update the tree.
|
|
|
|
if (rootContent != mContent)
|
|
|
|
mContent = rootContent;
|
|
|
|
}
|
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
// XXX: Invalidate parent-child relations for container accessible and its
|
|
|
|
// children because there's no good way to find insertion point of new child
|
|
|
|
// accessibles into accessible tree. We need to invalidate children even
|
|
|
|
// there's no inserted accessibles in the end because accessible children
|
|
|
|
// are created while parent recaches child accessibles.
|
|
|
|
container->InvalidateChildren();
|
2010-11-06 04:11:08 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Don't create new accessibles on content removal.
|
|
|
|
container = aContainerNode ?
|
|
|
|
GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
|
|
|
|
this;
|
2010-10-21 04:16:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EIsFromUserInput fromUserInput = esm->IsHandlingUserInputExternal() ?
|
|
|
|
eFromUserInput : eNoUserInput;
|
|
|
|
|
|
|
|
// Update the accessible tree in the case of content removal and fire events
|
|
|
|
// if allowed.
|
|
|
|
PRUint32 updateFlags =
|
|
|
|
UpdateTreeInternal(container, aStartNode, aEndNode,
|
|
|
|
aIsInsert, fireAllEvents, fromUserInput);
|
|
|
|
|
|
|
|
// Content insertion/removal is not cause of accessible tree change.
|
|
|
|
if (updateFlags == eNoAccessible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Check to see if change occurred inside an alert, and fire an EVENT_ALERT
|
|
|
|
// if it did.
|
|
|
|
if (aIsInsert && !(updateFlags & eAlertAccessible)) {
|
|
|
|
// XXX: tree traversal is perf issue, accessible should know if they are
|
|
|
|
// children of alert accessible to avoid this.
|
|
|
|
nsAccessible* ancestor = container;
|
|
|
|
while (ancestor) {
|
|
|
|
const nsRoleMapEntry* roleMapEntry = ancestor->GetRoleMapEntry();
|
|
|
|
if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
|
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT,
|
|
|
|
ancestor->GetNode(), AccEvent::eRemoveDupes,
|
|
|
|
fromUserInput);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't climb above this document.
|
|
|
|
if (ancestor == this)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ancestor = ancestor->GetParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fire nether value change nor reorder events if action is not from user
|
|
|
|
// input and document is loading. We are notified about changes in editor
|
|
|
|
// synchronously, so from user input flag is correct for value change events.
|
|
|
|
if (!fireAllEvents)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Fire value change event.
|
|
|
|
if (container->Role() == nsIAccessibleRole::ROLE_ENTRY) {
|
|
|
|
nsRefPtr<AccEvent> valueChangeEvent =
|
|
|
|
new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, container,
|
|
|
|
fromUserInput, AccEvent::eRemoveDupes);
|
|
|
|
FireDelayedAccessibleEvent(valueChangeEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fire reorder event so the MSAA clients know the children have changed. Also
|
|
|
|
// the event is used internally by MSAA part.
|
|
|
|
nsRefPtr<AccEvent> reorderEvent =
|
|
|
|
new AccEvent(nsIAccessibleEvent::EVENT_REORDER, container->GetNode(),
|
|
|
|
fromUserInput, AccEvent::eCoalesceFromSameSubtree);
|
|
|
|
if (reorderEvent)
|
|
|
|
FireDelayedAccessibleEvent(reorderEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocAccessible::RecreateAccessible(nsINode* aNode)
|
|
|
|
{
|
|
|
|
// XXX: we shouldn't recreate whole accessible subtree that happens when
|
|
|
|
// hide event is handled, instead we should subclass hide and show events
|
|
|
|
// to handle them separately and implement their coalescence with normal hide
|
|
|
|
// and show events.
|
|
|
|
|
|
|
|
nsAccessible* parent = nsnull;
|
|
|
|
|
|
|
|
// Fire hide event for old accessible.
|
|
|
|
nsAccessible* oldAccessible =
|
|
|
|
GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell);
|
|
|
|
if (oldAccessible) {
|
|
|
|
parent = oldAccessible->GetParent();
|
|
|
|
|
|
|
|
nsRefPtr<AccEvent> hideEvent = new AccHideEvent(oldAccessible, aNode,
|
|
|
|
eAutoDetect);
|
|
|
|
if (hideEvent)
|
|
|
|
FireDelayedAccessibleEvent(hideEvent);
|
|
|
|
|
|
|
|
// Unbind old accessible from tree.
|
|
|
|
parent->RemoveChild(oldAccessible);
|
|
|
|
|
|
|
|
if (oldAccessible->IsPrimaryForNode() &&
|
|
|
|
mNodeToAccessibleMap.Get(oldAccessible->GetNode()) == oldAccessible)
|
|
|
|
mNodeToAccessibleMap.Remove(oldAccessible->GetNode());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
parent = GetAccService()->GetContainerAccessible(aNode, mWeakShell);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get new accessible and fire show event.
|
|
|
|
parent->InvalidateChildren();
|
|
|
|
|
|
|
|
nsAccessible* newAccessible =
|
|
|
|
GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell);
|
|
|
|
if (newAccessible) {
|
|
|
|
nsRefPtr<AccEvent> showEvent = new AccShowEvent(newAccessible, aNode,
|
|
|
|
eAutoDetect);
|
|
|
|
if (showEvent)
|
|
|
|
FireDelayedAccessibleEvent(showEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fire reorder event.
|
|
|
|
if (oldAccessible || newAccessible) {
|
|
|
|
nsRefPtr<AccEvent> reorderEvent =
|
|
|
|
new AccEvent(nsIAccessibleEvent::EVENT_REORDER, parent->GetNode(),
|
|
|
|
eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
|
|
|
|
|
|
|
|
if (reorderEvent)
|
|
|
|
FireDelayedAccessibleEvent(reorderEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Protected members
|
|
|
|
|
2010-11-18 02:55:44 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::AddDependentIDsFor(nsAccessible* aRelProvider,
|
|
|
|
nsIAtom* aRelAttr)
|
|
|
|
{
|
|
|
|
for (PRUint32 idx = 0; idx < kRelationAttrsLen; idx++) {
|
|
|
|
nsIAtom* relAttr = *kRelationAttrs[idx];
|
|
|
|
if (aRelAttr && aRelAttr != relAttr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
IDRefsIterator iter(aRelProvider->GetContent(), relAttr);
|
|
|
|
while (true) {
|
|
|
|
const nsDependentSubstring id = iter.NextID();
|
|
|
|
if (id.IsEmpty())
|
|
|
|
break;
|
|
|
|
|
|
|
|
AttrRelProviderArray* providers = mDependentIDsHash.Get(id);
|
|
|
|
if (!providers) {
|
|
|
|
providers = new AttrRelProviderArray();
|
|
|
|
if (providers) {
|
|
|
|
if (!mDependentIDsHash.Put(id, providers)) {
|
|
|
|
delete providers;
|
|
|
|
providers = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (providers) {
|
|
|
|
AttrRelProvider* provider =
|
|
|
|
new AttrRelProvider(relAttr, aRelProvider->GetContent());
|
|
|
|
if (provider)
|
|
|
|
providers->AppendElement(provider);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the relation attribute is given then we don't have anything else to
|
|
|
|
// check.
|
|
|
|
if (aRelAttr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocAccessible::RemoveDependentIDsFor(nsAccessible* aRelProvider,
|
|
|
|
nsIAtom* aRelAttr)
|
|
|
|
{
|
|
|
|
for (PRUint32 idx = 0; idx < kRelationAttrsLen; idx++) {
|
|
|
|
nsIAtom* relAttr = *kRelationAttrs[idx];
|
|
|
|
if (aRelAttr && aRelAttr != *kRelationAttrs[idx])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
IDRefsIterator iter(aRelProvider->GetContent(), relAttr);
|
|
|
|
while (true) {
|
|
|
|
const nsDependentSubstring id = iter.NextID();
|
|
|
|
if (id.IsEmpty())
|
|
|
|
break;
|
|
|
|
|
|
|
|
AttrRelProviderArray* providers = mDependentIDsHash.Get(id);
|
|
|
|
if (providers) {
|
|
|
|
for (PRUint32 jdx = 0; jdx < providers->Length(); ) {
|
|
|
|
AttrRelProvider* provider = (*providers)[jdx];
|
|
|
|
if (provider->mRelAttr == relAttr &&
|
|
|
|
provider->mContent == aRelProvider->GetContent())
|
|
|
|
providers->RemoveElement(provider);
|
|
|
|
else
|
|
|
|
jdx++;
|
|
|
|
}
|
|
|
|
if (providers->Length() == 0)
|
|
|
|
mDependentIDsHash.Remove(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the relation attribute is given then we don't have anything else to
|
|
|
|
// check.
|
|
|
|
if (aRelAttr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-20 01:58:11 +00:00
|
|
|
void
|
2010-06-12 04:04:24 +00:00
|
|
|
nsDocAccessible::FireValueChangeForTextFields(nsAccessible *aAccessible)
|
2008-03-20 01:58:11 +00:00
|
|
|
{
|
2010-09-07 02:41:53 +00:00
|
|
|
if (aAccessible->Role() != nsIAccessibleRole::ROLE_ENTRY)
|
2008-03-20 01:58:11 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Dependent value change event for text changes in textfields
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> valueChangeEvent =
|
|
|
|
new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible,
|
2010-10-21 04:16:10 +00:00
|
|
|
eAutoDetect, AccEvent::eRemoveDupes);
|
2010-01-27 11:42:44 +00:00
|
|
|
FireDelayedAccessibleEvent(valueChangeEvent);
|
2008-03-20 01:58:11 +00:00
|
|
|
}
|
|
|
|
|
2007-07-25 11:54:15 +00:00
|
|
|
void
|
2007-09-05 08:22:17 +00:00
|
|
|
nsDocAccessible::FireTextChangeEventForText(nsIContent *aContent,
|
|
|
|
CharacterDataChangeInfo* aInfo,
|
|
|
|
PRBool aIsInserted)
|
2007-07-25 11:54:15 +00:00
|
|
|
{
|
2010-06-08 16:39:58 +00:00
|
|
|
if (!IsContentLoaded())
|
2007-08-06 03:19:37 +00:00
|
|
|
return;
|
|
|
|
|
2010-06-10 03:29:56 +00:00
|
|
|
PRInt32 contentOffset = aInfo->mChangeStart;
|
|
|
|
PRUint32 contentLength = aIsInserted ?
|
|
|
|
aInfo->mReplaceLength: // text has been added
|
|
|
|
aInfo->mChangeEnd - contentOffset; // text has been removed
|
|
|
|
|
|
|
|
if (contentLength == 0)
|
2007-07-25 11:54:15 +00:00
|
|
|
return;
|
|
|
|
|
2010-06-11 08:23:18 +00:00
|
|
|
nsAccessible *accessible = GetAccService()->GetAccessible(aContent);
|
2010-05-25 08:40:39 +00:00
|
|
|
if (!accessible)
|
2007-07-25 11:54:15 +00:00
|
|
|
return;
|
|
|
|
|
2010-06-10 03:29:56 +00:00
|
|
|
nsRefPtr<nsHyperTextAccessible> textAccessible =
|
|
|
|
do_QueryObject(accessible->GetParent());
|
2010-05-17 16:16:52 +00:00
|
|
|
if (!textAccessible)
|
2007-07-25 11:54:15 +00:00
|
|
|
return;
|
|
|
|
|
2010-07-02 01:50:03 +00:00
|
|
|
// Get offset within hypertext accessible and invalidate cached offsets after
|
|
|
|
// this child accessible.
|
|
|
|
PRInt32 offset = textAccessible->GetChildOffset(accessible, PR_TRUE);
|
2007-07-25 11:54:15 +00:00
|
|
|
|
2010-07-02 01:50:03 +00:00
|
|
|
// Get added or removed text.
|
2010-06-10 03:29:56 +00:00
|
|
|
nsIFrame* frame = aContent->GetPrimaryFrame();
|
|
|
|
if (!frame)
|
|
|
|
return;
|
2007-09-05 08:22:17 +00:00
|
|
|
|
2010-06-10 03:29:56 +00:00
|
|
|
PRUint32 textOffset = 0;
|
|
|
|
nsresult rv = textAccessible->ContentToRenderedOffset(frame, contentOffset,
|
|
|
|
&textOffset);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
2007-09-05 08:22:17 +00:00
|
|
|
|
2010-06-10 03:29:56 +00:00
|
|
|
nsAutoString text;
|
|
|
|
rv = accessible->AppendTextTo(text, textOffset, contentLength);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
2007-09-05 08:22:17 +00:00
|
|
|
|
2010-07-02 01:49:42 +00:00
|
|
|
if (text.IsEmpty())
|
2010-06-10 03:29:56 +00:00
|
|
|
return;
|
2007-07-25 11:54:15 +00:00
|
|
|
|
2010-06-10 03:29:56 +00:00
|
|
|
// Normally we only fire delayed events created from the node, not an
|
2010-08-25 02:08:28 +00:00
|
|
|
// accessible object. See the AccTextChangeEvent constructor for details
|
2010-06-10 03:29:56 +00:00
|
|
|
// about this exceptional case.
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
|
|
|
new AccTextChangeEvent(textAccessible, offset + textOffset, text,
|
2010-10-21 04:16:10 +00:00
|
|
|
aIsInserted);
|
2010-06-10 03:29:56 +00:00
|
|
|
FireDelayedAccessibleEvent(event);
|
2008-03-20 01:58:11 +00:00
|
|
|
|
2010-06-10 03:29:56 +00:00
|
|
|
FireValueChangeForTextFields(textAccessible);
|
2007-07-25 11:54:15 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible public member
|
2009-09-03 02:01:18 +00:00
|
|
|
nsresult
|
2010-06-11 08:23:18 +00:00
|
|
|
nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType, nsINode *aNode,
|
2010-08-25 02:08:28 +00:00
|
|
|
AccEvent::EEventRule aAllowDupes,
|
2010-01-20 11:16:32 +00:00
|
|
|
EIsFromUserInput aIsFromUserInput)
|
2007-04-17 04:45:42 +00:00
|
|
|
{
|
2010-08-25 02:08:28 +00:00
|
|
|
nsRefPtr<AccEvent> event =
|
2010-10-21 04:16:10 +00:00
|
|
|
new AccEvent(aEventType, aNode, aIsFromUserInput, aAllowDupes);
|
2007-04-17 04:45:42 +00:00
|
|
|
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2008-03-17 08:13:10 +00:00
|
|
|
return FireDelayedAccessibleEvent(event);
|
2007-04-17 04:45:42 +00:00
|
|
|
}
|
|
|
|
|
2009-12-10 19:12:19 +00:00
|
|
|
// nsDocAccessible public member
|
2007-04-17 04:45:42 +00:00
|
|
|
nsresult
|
2010-08-25 02:08:28 +00:00
|
|
|
nsDocAccessible::FireDelayedAccessibleEvent(AccEvent* aEvent)
|
2005-06-10 13:57:27 +00:00
|
|
|
{
|
2009-09-07 16:46:56 +00:00
|
|
|
NS_ENSURE_ARG(aEvent);
|
2010-06-08 16:39:58 +00:00
|
|
|
NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent)
|
2009-09-07 16:46:56 +00:00
|
|
|
|
2010-01-27 11:42:08 +00:00
|
|
|
if (mEventQueue)
|
2010-01-27 11:42:44 +00:00
|
|
|
mEventQueue->Push(aEvent);
|
2009-09-07 16:46:56 +00:00
|
|
|
|
2010-01-27 11:42:08 +00:00
|
|
|
return NS_OK;
|
2009-09-07 16:46:56 +00:00
|
|
|
}
|
2007-08-21 03:16:27 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
// nsDocAccessible public member
|
2010-01-27 11:42:08 +00:00
|
|
|
void
|
2010-08-25 02:08:28 +00:00
|
|
|
nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent)
|
2010-10-21 04:16:10 +00:00
|
|
|
{
|
|
|
|
nsAccessible* accessible = aEvent->GetAccessible();
|
|
|
|
if (!accessible)
|
|
|
|
return;
|
2010-01-27 11:42:08 +00:00
|
|
|
|
|
|
|
PRUint32 eventType = aEvent->GetEventType();
|
2007-09-28 20:55:46 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
|
|
|
|
nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryObject(accessible);
|
|
|
|
PRInt32 caretOffset;
|
|
|
|
if (accessibleText &&
|
|
|
|
NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
|
2007-08-17 18:21:49 +00:00
|
|
|
#ifdef DEBUG_A11Y
|
2010-10-21 04:16:10 +00:00
|
|
|
PRUnichar chAtOffset;
|
|
|
|
accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
|
|
|
|
printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
|
2007-12-11 03:30:02 +00:00
|
|
|
#endif
|
|
|
|
#ifdef DEBUG_CARET
|
2010-10-21 04:16:10 +00:00
|
|
|
// Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
|
|
|
|
// line-number object attribute on it
|
|
|
|
nsAccessible* focusedAcc =
|
|
|
|
GetAccService()->GetAccessible(gLastFocusedNode);
|
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, focusedAcc);
|
2007-07-13 17:19:40 +00:00
|
|
|
#endif
|
2010-10-21 04:16:10 +00:00
|
|
|
nsRefPtr<AccEvent> caretMoveEvent =
|
2010-08-25 02:08:28 +00:00
|
|
|
new AccCaretMoveEvent(accessible, caretOffset);
|
2010-10-21 04:16:10 +00:00
|
|
|
if (!caretMoveEvent)
|
|
|
|
return;
|
2008-02-02 17:02:09 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
nsEventShell::FireEvent(caretMoveEvent);
|
2008-02-02 17:02:09 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
PRInt32 selectionCount;
|
|
|
|
accessibleText->GetSelectionCount(&selectionCount);
|
|
|
|
if (selectionCount) { // There's a selection so fire selection change as well
|
|
|
|
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
|
2010-01-18 16:16:07 +00:00
|
|
|
accessible);
|
2008-01-24 14:07:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-21 04:16:10 +00:00
|
|
|
else {
|
|
|
|
nsEventShell::FireEvent(aEvent);
|
2008-01-22 14:43:18 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
// Post event processing
|
|
|
|
if (eventType == nsIAccessibleEvent::EVENT_HIDE)
|
|
|
|
ShutdownChildrenInSubtree(accessible);
|
2008-01-22 14:43:18 +00:00
|
|
|
}
|
2005-05-03 03:46:51 +00:00
|
|
|
}
|
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
PRUint32
|
|
|
|
nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
|
|
|
|
nsIContent* aStartNode,
|
|
|
|
nsIContent* aEndNode,
|
|
|
|
PRBool aIsInsert,
|
|
|
|
PRBool aFireAllEvents,
|
|
|
|
EIsFromUserInput aFromUserInput)
|
2005-05-03 03:46:51 +00:00
|
|
|
{
|
2010-10-21 04:16:10 +00:00
|
|
|
PRUint32 updateFlags = eNoAccessible;
|
|
|
|
for (nsIContent* node = aStartNode; node != aEndNode;
|
|
|
|
node = node->GetNextSibling()) {
|
|
|
|
|
|
|
|
// Tree update triggers for content insertion even if no content was
|
|
|
|
// inserted actually, check if the given content has a frame to discard
|
|
|
|
// this case early.
|
|
|
|
if (aIsInsert && !node->GetPrimaryFrame())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
nsAccessible* accessible = aIsInsert ?
|
|
|
|
GetAccService()->GetAccessibleInWeakShell(node, mWeakShell) :
|
|
|
|
GetCachedAccessible(node);
|
|
|
|
|
|
|
|
if (!accessible) {
|
|
|
|
updateFlags |= UpdateTreeInternal(aContainer, node->GetFirstChild(),
|
|
|
|
nsnull, aIsInsert, aFireAllEvents,
|
|
|
|
aFromUserInput);
|
|
|
|
continue;
|
2007-10-01 18:27:13 +00:00
|
|
|
}
|
2009-06-25 02:08:53 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
updateFlags |= eAccessible;
|
2005-06-10 13:57:27 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
// Fire show/hide event.
|
|
|
|
if (aFireAllEvents) {
|
|
|
|
nsRefPtr<AccEvent> event;
|
|
|
|
if (aIsInsert)
|
|
|
|
event = new AccShowEvent(accessible, node, aFromUserInput);
|
|
|
|
else
|
|
|
|
event = new AccHideEvent(accessible, node, aFromUserInput);
|
2007-06-30 02:49:32 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
if (event)
|
|
|
|
FireDelayedAccessibleEvent(event);
|
|
|
|
}
|
2006-08-11 17:21:56 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
if (aIsInsert) {
|
|
|
|
const nsRoleMapEntry* roleMapEntry = accessible->GetRoleMapEntry();
|
|
|
|
if (roleMapEntry) {
|
|
|
|
if (roleMapEntry->role == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
|
|
|
// Fire EVENT_MENUPOPUP_START if ARIA menu appears.
|
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
|
|
|
|
node, AccEvent::eRemoveDupes, aFromUserInput);
|
|
|
|
|
|
|
|
} else if (roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
|
|
|
|
// Fire EVENT_ALERT if ARIA alert appears.
|
|
|
|
updateFlags = eAlertAccessible;
|
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, node,
|
|
|
|
AccEvent::eRemoveDupes, aFromUserInput);
|
2007-10-06 16:24:57 +00:00
|
|
|
}
|
|
|
|
}
|
2005-05-03 03:46:51 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
// If focused node has been shown then it means its frame was recreated
|
|
|
|
// while it's focused. Fire focus event on new focused accessible. If
|
|
|
|
// the queue contains focus event for this node then it's suppressed by
|
|
|
|
// this one.
|
|
|
|
if (node == gLastFocusedNode) {
|
|
|
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
|
|
|
|
node, AccEvent::eCoalesceFromSameDocument,
|
|
|
|
aFromUserInput);
|
2006-04-21 17:39:32 +00:00
|
|
|
}
|
2010-10-21 04:16:10 +00:00
|
|
|
} else {
|
|
|
|
// Update the tree for content removal.
|
|
|
|
aContainer->RemoveChild(accessible);
|
|
|
|
UncacheChildrenInSubtree(accessible);
|
2005-06-10 13:57:27 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-15 08:37:38 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
return updateFlags;
|
2003-04-28 10:24:52 +00:00
|
|
|
}
|
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::UncacheChildrenInSubtree(nsAccessible* aRoot)
|
2007-10-06 16:24:57 +00:00
|
|
|
{
|
2010-10-21 04:16:10 +00:00
|
|
|
PRUint32 count = aRoot->GetCachedChildCount();
|
|
|
|
for (PRUint32 idx = 0; idx < count; idx++)
|
|
|
|
UncacheChildrenInSubtree(aRoot->GetCachedChildAt(idx));
|
2007-10-06 16:24:57 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
if (aRoot->IsPrimaryForNode() &&
|
|
|
|
mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
|
|
|
|
mNodeToAccessibleMap.Remove(aRoot->GetNode());
|
|
|
|
}
|
2007-10-06 16:24:57 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
void
|
|
|
|
nsDocAccessible::ShutdownChildrenInSubtree(nsAccessible* aAccessible)
|
|
|
|
{
|
|
|
|
// Traverse through children and shutdown them before this accessible. When
|
|
|
|
// child gets shutdown then it removes itself from children array of its
|
|
|
|
//parent. Use jdx index to process the cases if child is not attached to the
|
|
|
|
// parent and as result doesn't remove itself from its children.
|
|
|
|
PRUint32 count = aAccessible->GetCachedChildCount();
|
|
|
|
for (PRUint32 idx = 0, jdx = 0; idx < count; idx++) {
|
|
|
|
nsAccessible* child = aAccessible->GetCachedChildAt(jdx);
|
|
|
|
if (!child->IsBoundToParent()) {
|
|
|
|
NS_ERROR("Parent refers to a child, child doesn't refer to parent!");
|
|
|
|
jdx++;
|
2010-07-02 01:49:42 +00:00
|
|
|
}
|
2009-09-09 09:03:14 +00:00
|
|
|
|
2010-10-21 04:16:10 +00:00
|
|
|
ShutdownChildrenInSubtree(child);
|
2007-10-06 16:24:57 +00:00
|
|
|
}
|
|
|
|
|
2010-11-12 19:00:55 +00:00
|
|
|
UnbindFromDocument(aAccessible);
|
2007-10-06 16:24:57 +00:00
|
|
|
}
|
2010-10-21 04:16:10 +00:00
|
|
|
|