2008-10-16 02:12:05 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Mozilla Foundation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2007
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsCoreUtils.h"
|
|
|
|
#include "nsAccUtils.h"
|
|
|
|
|
|
|
|
#include "nsIAccessibleStates.h"
|
|
|
|
#include "nsIAccessibleTypes.h"
|
|
|
|
|
2010-04-26 23:52:03 -07:00
|
|
|
#include "nsAccessibilityService.h"
|
2008-10-16 02:12:05 -07:00
|
|
|
#include "nsAccessibilityAtoms.h"
|
|
|
|
#include "nsARIAMap.h"
|
2010-04-26 23:52:03 -07:00
|
|
|
#include "nsDocAccessible.h"
|
|
|
|
#include "nsHyperTextAccessible.h"
|
|
|
|
#include "nsHTMLTableAccessible.h"
|
2011-01-31 19:00:45 -08:00
|
|
|
#include "nsTextAccessible.h"
|
2009-08-19 23:45:19 -07:00
|
|
|
#include "nsXULTreeGridAccessible.h"
|
2008-10-17 03:10:43 -07:00
|
|
|
|
2008-10-16 02:12:05 -07:00
|
|
|
#include "nsIDOMXULContainerElement.h"
|
|
|
|
#include "nsIDOMXULSelectCntrlEl.h"
|
|
|
|
#include "nsIDOMXULSelectCntrlItemEl.h"
|
|
|
|
#include "nsWhitespaceTokenizer.h"
|
2009-09-10 18:07:56 -07:00
|
|
|
#include "nsComponentManagerUtils.h"
|
2008-10-16 02:12:05 -07:00
|
|
|
|
|
|
|
void
|
|
|
|
nsAccUtils::GetAccAttr(nsIPersistentProperties *aAttributes,
|
|
|
|
nsIAtom *aAttrName, nsAString& aAttrValue)
|
|
|
|
{
|
|
|
|
aAttrValue.Truncate();
|
|
|
|
|
2010-03-08 07:45:00 -08:00
|
|
|
aAttributes->GetStringProperty(nsAtomCString(aAttrName), aAttrValue);
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsAccUtils::SetAccAttr(nsIPersistentProperties *aAttributes,
|
|
|
|
nsIAtom *aAttrName, const nsAString& aAttrValue)
|
|
|
|
{
|
|
|
|
nsAutoString oldValue;
|
|
|
|
nsCAutoString attrName;
|
|
|
|
|
2010-03-08 07:45:00 -08:00
|
|
|
aAttributes->SetStringProperty(nsAtomCString(aAttrName), aAttrValue, oldValue);
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsAccUtils::SetAccGroupAttrs(nsIPersistentProperties *aAttributes,
|
2010-01-06 02:36:50 -08:00
|
|
|
PRInt32 aLevel, PRInt32 aSetSize,
|
|
|
|
PRInt32 aPosInSet)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
|
|
|
nsAutoString value;
|
|
|
|
|
|
|
|
if (aLevel) {
|
|
|
|
value.AppendInt(aLevel);
|
|
|
|
SetAccAttr(aAttributes, nsAccessibilityAtoms::level, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aSetSize && aPosInSet) {
|
|
|
|
value.Truncate();
|
|
|
|
value.AppendInt(aPosInSet);
|
|
|
|
SetAccAttr(aAttributes, nsAccessibilityAtoms::posinset, value);
|
|
|
|
|
|
|
|
value.Truncate();
|
|
|
|
value.AppendInt(aSetSize);
|
|
|
|
SetAccAttr(aAttributes, nsAccessibilityAtoms::setsize, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-12 11:07:38 -08:00
|
|
|
PRInt32
|
2010-06-11 21:04:50 -07:00
|
|
|
nsAccUtils::GetDefaultLevel(nsAccessible *aAccessible)
|
2010-01-12 11:07:38 -08:00
|
|
|
{
|
2010-09-06 19:41:53 -07:00
|
|
|
PRUint32 role = aAccessible->Role();
|
2010-01-12 11:07:38 -08:00
|
|
|
|
|
|
|
if (role == nsIAccessibleRole::ROLE_OUTLINEITEM)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (role == nsIAccessibleRole::ROLE_ROW) {
|
2010-06-11 21:04:50 -07:00
|
|
|
nsAccessible *parent = aAccessible->GetParent();
|
2010-09-06 19:41:53 -07:00
|
|
|
if (parent && parent->Role() == nsIAccessibleRole::ROLE_TREE_TABLE) {
|
2010-01-12 11:07:38 -08:00
|
|
|
// It is a row inside flatten treegrid. Group level is always 1 until it
|
|
|
|
// is overriden by aria-level attribute.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
2010-06-11 21:04:50 -07:00
|
|
|
nsAccUtils::GetARIAOrDefaultLevel(nsAccessible *aAccessible)
|
2010-01-12 11:07:38 -08:00
|
|
|
{
|
|
|
|
PRInt32 level = 0;
|
2010-06-11 21:04:50 -07:00
|
|
|
nsCoreUtils::GetUIntAttr(aAccessible->GetContent(),
|
|
|
|
nsAccessibilityAtoms::aria_level, &level);
|
2010-01-12 11:07:38 -08:00
|
|
|
|
|
|
|
if (level != 0)
|
|
|
|
return level;
|
|
|
|
|
2010-06-11 21:04:50 -07:00
|
|
|
return GetDefaultLevel(aAccessible);
|
2010-01-12 11:07:38 -08:00
|
|
|
}
|
|
|
|
|
2008-10-16 02:12:05 -07:00
|
|
|
void
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccUtils::GetPositionAndSizeForXULSelectControlItem(nsIContent *aContent,
|
2010-01-06 02:36:50 -08:00
|
|
|
PRInt32 *aPosInSet,
|
|
|
|
PRInt32 *aSetSize)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> item(do_QueryInterface(aContent));
|
2008-10-16 02:12:05 -07:00
|
|
|
if (!item)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlElement> control;
|
|
|
|
item->GetControl(getter_AddRefs(control));
|
|
|
|
if (!control)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PRUint32 itemsCount = 0;
|
|
|
|
control->GetItemCount(&itemsCount);
|
|
|
|
|
|
|
|
PRInt32 indexOf = 0;
|
|
|
|
control->GetIndexOfItem(item, &indexOf);
|
|
|
|
|
2010-01-06 02:36:50 -08:00
|
|
|
*aSetSize = itemsCount;
|
|
|
|
*aPosInSet = indexOf;
|
|
|
|
|
2008-10-16 02:12:05 -07:00
|
|
|
for (PRUint32 index = 0; index < itemsCount; index++) {
|
|
|
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> currItem;
|
|
|
|
control->GetItemAtIndex(index, getter_AddRefs(currItem));
|
2010-06-28 06:22:49 -07:00
|
|
|
nsCOMPtr<nsINode> currNode(do_QueryInterface(currItem));
|
|
|
|
|
|
|
|
nsAccessible* itemAcc = GetAccService()->GetAccessible(currNode);
|
2008-10-16 02:12:05 -07:00
|
|
|
|
|
|
|
if (!itemAcc ||
|
2008-10-17 03:10:43 -07:00
|
|
|
State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
|
2010-01-06 02:36:50 -08:00
|
|
|
(*aSetSize)--;
|
2008-10-16 02:12:05 -07:00
|
|
|
if (index < static_cast<PRUint32>(indexOf))
|
2010-01-06 02:36:50 -08:00
|
|
|
(*aPosInSet)--;
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-06 02:36:50 -08:00
|
|
|
(*aPosInSet)++; // group position is 1-index based.
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIContent *aContent,
|
2010-01-06 02:36:50 -08:00
|
|
|
PRInt32 *aPosInSet,
|
|
|
|
PRInt32 *aSetSize)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCOMPtr<nsIDOMXULContainerItemElement> item(do_QueryInterface(aContent));
|
2008-10-16 02:12:05 -07:00
|
|
|
if (!item)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMXULContainerElement> container;
|
|
|
|
item->GetParentContainer(getter_AddRefs(container));
|
|
|
|
if (!container)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Get item count.
|
|
|
|
PRUint32 itemsCount = 0;
|
|
|
|
container->GetItemCount(&itemsCount);
|
|
|
|
|
|
|
|
// Get item index.
|
|
|
|
PRInt32 indexOf = 0;
|
|
|
|
container->GetIndexOfItem(item, &indexOf);
|
|
|
|
|
|
|
|
// Calculate set size and position in the set.
|
2010-01-06 02:36:50 -08:00
|
|
|
*aSetSize = 0, *aPosInSet = 0;
|
2008-10-16 02:12:05 -07:00
|
|
|
for (PRInt32 index = indexOf; index >= 0; index--) {
|
|
|
|
nsCOMPtr<nsIDOMXULElement> item;
|
|
|
|
container->GetItemAtIndex(index, getter_AddRefs(item));
|
2010-06-28 06:22:49 -07:00
|
|
|
nsCOMPtr<nsINode> itemNode(do_QueryInterface(item));
|
2008-10-16 02:12:05 -07:00
|
|
|
|
2010-06-28 06:22:49 -07:00
|
|
|
nsAccessible* itemAcc = GetAccService()->GetAccessible(itemNode);
|
2008-10-16 02:12:05 -07:00
|
|
|
|
|
|
|
if (itemAcc) {
|
2008-10-17 03:10:43 -07:00
|
|
|
PRUint32 itemRole = Role(itemAcc);
|
2008-10-16 02:12:05 -07:00
|
|
|
if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
|
|
|
|
break; // We reached the beginning of our group.
|
|
|
|
|
2008-10-17 03:10:43 -07:00
|
|
|
PRUint32 itemState = State(itemAcc);
|
2008-10-16 02:12:05 -07:00
|
|
|
if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE)) {
|
2010-01-06 02:36:50 -08:00
|
|
|
(*aSetSize)++;
|
|
|
|
(*aPosInSet)++;
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (PRInt32 index = indexOf + 1; index < static_cast<PRInt32>(itemsCount);
|
|
|
|
index++) {
|
|
|
|
nsCOMPtr<nsIDOMXULElement> item;
|
|
|
|
container->GetItemAtIndex(index, getter_AddRefs(item));
|
2010-06-28 06:22:49 -07:00
|
|
|
nsCOMPtr<nsINode> itemNode(do_QueryInterface(item));
|
2008-10-16 02:12:05 -07:00
|
|
|
|
2010-06-28 06:22:49 -07:00
|
|
|
nsAccessible* itemAcc = GetAccService()->GetAccessible(itemNode);
|
2008-10-16 02:12:05 -07:00
|
|
|
|
|
|
|
if (itemAcc) {
|
2008-10-17 03:10:43 -07:00
|
|
|
PRUint32 itemRole = Role(itemAcc);
|
2008-10-16 02:12:05 -07:00
|
|
|
if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
|
|
|
|
break; // We reached the end of our group.
|
|
|
|
|
2008-10-17 03:10:43 -07:00
|
|
|
PRUint32 itemState = State(itemAcc);
|
2008-10-16 02:12:05 -07:00
|
|
|
if (!(itemState & nsIAccessibleStates::STATE_INVISIBLE))
|
2010-01-06 02:36:50 -08:00
|
|
|
(*aSetSize)++;
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
}
|
2010-01-06 02:36:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccUtils::GetLevelForXULContainerItem(nsIContent *aContent)
|
2010-01-06 02:36:50 -08:00
|
|
|
{
|
2010-06-11 01:23:18 -07:00
|
|
|
nsCOMPtr<nsIDOMXULContainerItemElement> item(do_QueryInterface(aContent));
|
2010-01-06 02:36:50 -08:00
|
|
|
if (!item)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMXULContainerElement> container;
|
|
|
|
item->GetParentContainer(getter_AddRefs(container));
|
|
|
|
if (!container)
|
|
|
|
return 0;
|
2008-10-16 02:12:05 -07:00
|
|
|
|
|
|
|
// Get level of the item.
|
|
|
|
PRInt32 level = -1;
|
|
|
|
while (container) {
|
|
|
|
level++;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMXULContainerElement> parentContainer;
|
|
|
|
container->GetParentContainer(getter_AddRefs(parentContainer));
|
|
|
|
parentContainer.swap(container);
|
|
|
|
}
|
2010-01-06 02:36:50 -08:00
|
|
|
|
|
|
|
return level;
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
|
|
|
|
nsIContent *aStartContent,
|
|
|
|
nsIContent *aTopContent)
|
|
|
|
{
|
2009-01-12 22:08:46 -08:00
|
|
|
nsAutoString atomic, live, relevant, busy;
|
2008-10-16 02:12:05 -07:00
|
|
|
nsIContent *ancestor = aStartContent;
|
|
|
|
while (ancestor) {
|
2009-02-18 22:56:19 -08:00
|
|
|
|
|
|
|
// container-relevant attribute
|
2008-10-16 02:12:05 -07:00
|
|
|
if (relevant.IsEmpty() &&
|
2009-01-12 09:20:34 -08:00
|
|
|
nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_relevant) &&
|
2008-10-16 02:12:05 -07:00
|
|
|
ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_relevant, relevant))
|
|
|
|
SetAccAttr(aAttributes, nsAccessibilityAtoms::containerRelevant, relevant);
|
|
|
|
|
2009-06-19 10:44:13 -07:00
|
|
|
// container-live, and container-live-role attributes
|
2009-02-18 22:56:19 -08:00
|
|
|
if (live.IsEmpty()) {
|
2010-06-11 01:23:18 -07:00
|
|
|
nsRoleMapEntry *role = GetRoleMapEntry(ancestor);
|
2009-02-18 22:56:19 -08:00
|
|
|
if (nsAccUtils::HasDefinedARIAToken(ancestor,
|
|
|
|
nsAccessibilityAtoms::aria_live)) {
|
|
|
|
ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live,
|
|
|
|
live);
|
2009-06-19 10:44:13 -07:00
|
|
|
} else if (role) {
|
|
|
|
GetLiveAttrValue(role->liveAttRule, live);
|
|
|
|
}
|
|
|
|
if (!live.IsEmpty()) {
|
2009-02-18 22:56:19 -08:00
|
|
|
SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
|
|
|
|
if (role) {
|
2009-06-17 07:22:23 -07:00
|
|
|
nsAccUtils::SetAccAttr(aAttributes,
|
|
|
|
nsAccessibilityAtoms::containerLiveRole,
|
|
|
|
NS_ConvertASCIItoUTF16(role->roleString));
|
2009-02-18 22:56:19 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-10-16 02:12:05 -07:00
|
|
|
|
2009-02-18 22:56:19 -08:00
|
|
|
// container-atomic attribute
|
2008-10-16 02:12:05 -07:00
|
|
|
if (atomic.IsEmpty() &&
|
2009-01-12 09:20:34 -08:00
|
|
|
nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_atomic) &&
|
2008-10-16 02:12:05 -07:00
|
|
|
ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic, atomic))
|
|
|
|
SetAccAttr(aAttributes, nsAccessibilityAtoms::containerAtomic, atomic);
|
|
|
|
|
2009-02-18 22:56:19 -08:00
|
|
|
// container-busy attribute
|
2008-10-16 02:12:05 -07:00
|
|
|
if (busy.IsEmpty() &&
|
2009-01-12 09:20:34 -08:00
|
|
|
nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_busy) &&
|
2008-10-16 02:12:05 -07:00
|
|
|
ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_busy, busy))
|
|
|
|
SetAccAttr(aAttributes, nsAccessibilityAtoms::containerBusy, busy);
|
|
|
|
|
|
|
|
if (ancestor == aTopContent)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ancestor = ancestor->GetParent();
|
|
|
|
if (!ancestor)
|
|
|
|
ancestor = aTopContent; // Use <body>/<frameset>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-12 09:20:34 -08:00
|
|
|
PRBool
|
|
|
|
nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
|
|
|
|
{
|
2009-04-19 23:06:19 -07:00
|
|
|
NS_ASSERTION(aContent, "aContent is null in call to HasDefinedARIAToken!");
|
|
|
|
|
2009-01-12 09:20:34 -08:00
|
|
|
if (!aContent->HasAttr(kNameSpaceID_None, aAtom) ||
|
|
|
|
aContent->AttrValueIs(kNameSpaceID_None, aAtom,
|
|
|
|
nsAccessibilityAtoms::_empty, eCaseMatters) ||
|
|
|
|
aContent->AttrValueIs(kNameSpaceID_None, aAtom,
|
|
|
|
nsAccessibilityAtoms::_undefined, eCaseMatters)) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *
|
|
|
|
nsAccUtils::GetAncestorWithRole(nsAccessible *aDescendant, PRUint32 aRole)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *document = aDescendant->GetDocAccessible();
|
|
|
|
nsAccessible *parent = aDescendant;
|
|
|
|
while ((parent = parent->GetParent())) {
|
2010-09-06 19:41:53 -07:00
|
|
|
PRUint32 testRole = parent->Role();
|
2010-06-11 01:23:18 -07:00
|
|
|
if (testRole == aRole)
|
|
|
|
return parent;
|
|
|
|
|
|
|
|
if (parent == document)
|
2008-10-16 02:12:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *
|
|
|
|
nsAccUtils::GetSelectableContainer(nsAccessible *aAccessible, PRUint32 aState)
|
2009-12-11 11:38:55 -08:00
|
|
|
{
|
|
|
|
if (!aAccessible)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
if (!(aState & nsIAccessibleStates::STATE_SELECTABLE))
|
|
|
|
return nsnull;
|
|
|
|
|
2010-09-01 17:46:59 -07:00
|
|
|
nsAccessible* parent = aAccessible;
|
|
|
|
while ((parent = parent->GetParent()) && !parent->IsSelect()) {
|
|
|
|
if (Role(parent) == nsIAccessibleRole::ROLE_PANE)
|
2009-12-11 11:38:55 -08:00
|
|
|
return nsnull;
|
|
|
|
}
|
2010-06-11 01:23:18 -07:00
|
|
|
return parent;
|
2009-12-11 11:38:55 -08:00
|
|
|
}
|
|
|
|
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *
|
|
|
|
nsAccUtils::GetMultiSelectableContainer(nsINode *aNode)
|
2009-12-11 11:38:55 -08:00
|
|
|
{
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessible *accessible = GetAccService()->GetAccessible(aNode);
|
|
|
|
nsAccessible *container = GetSelectableContainer(accessible,
|
|
|
|
State(accessible));
|
2009-12-11 11:38:55 -08:00
|
|
|
|
|
|
|
if (State(container) & nsIAccessibleStates::STATE_MULTISELECTABLE)
|
2010-06-11 01:23:18 -07:00
|
|
|
return container;
|
2009-12-11 11:38:55 -08:00
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2009-09-10 18:07:56 -07:00
|
|
|
PRBool
|
2010-06-11 21:04:50 -07:00
|
|
|
nsAccUtils::IsARIASelected(nsAccessible *aAccessible)
|
2009-09-10 18:07:56 -07:00
|
|
|
{
|
2010-06-11 21:04:50 -07:00
|
|
|
return aAccessible->GetContent()->
|
|
|
|
AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected,
|
|
|
|
nsAccessibilityAtoms::_true, eCaseMatters);
|
2009-09-10 18:07:56 -07:00
|
|
|
}
|
|
|
|
|
2011-01-27 21:15:22 -08:00
|
|
|
nsHyperTextAccessible*
|
2010-11-29 08:03:29 -08:00
|
|
|
nsAccUtils::GetTextAccessibleFromSelection(nsISelection* aSelection)
|
2008-10-28 01:43:07 -07:00
|
|
|
{
|
|
|
|
// Get accessible from selection's focus DOM point (the DOM point where
|
|
|
|
// selection is ended).
|
|
|
|
|
2010-05-25 01:12:43 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> focusDOMNode;
|
|
|
|
aSelection->GetFocusNode(getter_AddRefs(focusDOMNode));
|
|
|
|
if (!focusDOMNode)
|
2008-10-28 01:43:07 -07:00
|
|
|
return nsnull;
|
|
|
|
|
2008-12-16 02:14:20 -08:00
|
|
|
PRInt32 focusOffset = 0;
|
|
|
|
aSelection->GetFocusOffset(&focusOffset);
|
|
|
|
|
2010-05-25 01:12:43 -07:00
|
|
|
nsCOMPtr<nsINode> focusNode(do_QueryInterface(focusDOMNode));
|
|
|
|
nsCOMPtr<nsINode> resultNode =
|
2008-12-16 02:14:20 -08:00
|
|
|
nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
|
2010-06-30 19:18:08 -07:00
|
|
|
nsCOMPtr<nsIWeakReference> weakShell(nsCoreUtils::GetWeakShellFor(resultNode));
|
2008-10-28 01:43:07 -07:00
|
|
|
|
|
|
|
// Get text accessible containing the result node.
|
2010-06-30 19:18:08 -07:00
|
|
|
nsAccessible* accessible =
|
|
|
|
GetAccService()->GetAccessibleOrContainer(resultNode, weakShell);
|
|
|
|
if (!accessible) {
|
|
|
|
NS_NOTREACHED("No nsIAccessibleText for selection change event!");
|
|
|
|
return nsnull;
|
2008-10-28 01:43:07 -07:00
|
|
|
}
|
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
do {
|
2011-01-27 21:15:22 -08:00
|
|
|
nsHyperTextAccessible* textAcc = accessible->AsHyperText();
|
2010-11-29 08:03:29 -08:00
|
|
|
if (textAcc)
|
2010-06-30 19:18:08 -07:00
|
|
|
return textAcc;
|
2010-11-29 08:03:29 -08:00
|
|
|
|
2010-06-30 19:18:08 -07:00
|
|
|
} while (accessible = accessible->GetParent());
|
|
|
|
|
|
|
|
NS_NOTREACHED("We must reach document accessible implementing nsIAccessibleText!");
|
2008-10-28 01:43:07 -07:00
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2008-10-16 02:12:05 -07:00
|
|
|
nsresult
|
|
|
|
nsAccUtils::ConvertToScreenCoords(PRInt32 aX, PRInt32 aY,
|
|
|
|
PRUint32 aCoordinateType,
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessNode *aAccessNode,
|
2008-10-16 02:12:05 -07:00
|
|
|
nsIntPoint *aCoords)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aCoords);
|
|
|
|
|
|
|
|
aCoords->MoveTo(aX, aY);
|
|
|
|
|
|
|
|
switch (aCoordinateType) {
|
|
|
|
case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE:
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aAccessNode);
|
|
|
|
*aCoords += GetScreenCoordsForWindow(aAccessNode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE:
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aAccessNode);
|
|
|
|
*aCoords += GetScreenCoordsForParent(aAccessNode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsAccUtils::ConvertScreenCoordsTo(PRInt32 *aX, PRInt32 *aY,
|
|
|
|
PRUint32 aCoordinateType,
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccessNode *aAccessNode)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
|
|
|
switch (aCoordinateType) {
|
|
|
|
case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE:
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aAccessNode);
|
|
|
|
nsIntPoint coords = nsAccUtils::GetScreenCoordsForWindow(aAccessNode);
|
|
|
|
*aX -= coords.x;
|
|
|
|
*aY -= coords.y;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE:
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aAccessNode);
|
|
|
|
nsIntPoint coords = nsAccUtils::GetScreenCoordsForParent(aAccessNode);
|
|
|
|
*aX -= coords.x;
|
|
|
|
*aY -= coords.y;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIntPoint
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccUtils::GetScreenCoordsForWindow(nsAccessNode *aAccessNode)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
2010-06-11 01:23:18 -07:00
|
|
|
return nsCoreUtils::GetScreenCoordsForWindow(aAccessNode->GetNode());
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIntPoint
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccUtils::GetScreenCoordsForParent(nsAccessNode *aAccessNode)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
2010-06-11 21:04:35 -07:00
|
|
|
nsAccessible *parent =
|
2010-06-30 19:18:08 -07:00
|
|
|
GetAccService()->GetContainerAccessible(aAccessNode->GetNode(),
|
|
|
|
aAccessNode->GetWeakShell());
|
2008-10-16 02:12:05 -07:00
|
|
|
if (!parent)
|
|
|
|
return nsIntPoint(0, 0);
|
|
|
|
|
|
|
|
nsIFrame *parentFrame = parent->GetFrame();
|
|
|
|
if (!parentFrame)
|
|
|
|
return nsIntPoint(0, 0);
|
|
|
|
|
|
|
|
nsIntRect parentRect = parentFrame->GetScreenRectExternal();
|
|
|
|
return nsIntPoint(parentRect.x, parentRect.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRoleMapEntry*
|
2010-06-11 01:23:18 -07:00
|
|
|
nsAccUtils::GetRoleMapEntry(nsINode *aNode)
|
2008-10-16 02:12:05 -07:00
|
|
|
{
|
2008-10-17 03:10:43 -07:00
|
|
|
nsIContent *content = nsCoreUtils::GetRoleContent(aNode);
|
2008-10-16 02:12:05 -07:00
|
|
|
nsAutoString roleString;
|
2009-08-31 06:12:08 -07:00
|
|
|
if (!content ||
|
|
|
|
!content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::role, roleString) ||
|
|
|
|
roleString.IsEmpty()) {
|
|
|
|
// We treat role="" as if the role attribute is absent (per aria spec:8.1.1)
|
2008-10-16 02:12:05 -07:00
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWhitespaceTokenizer tokenizer(roleString);
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
// Do a binary search through table for the next role in role list
|
2009-06-30 14:29:54 -07:00
|
|
|
NS_LossyConvertUTF16toASCII role(tokenizer.nextToken());
|
|
|
|
PRUint32 low = 0;
|
|
|
|
PRUint32 high = nsARIAMap::gWAIRoleMapLength;
|
|
|
|
while (low < high) {
|
|
|
|
PRUint32 index = (low + high) / 2;
|
|
|
|
PRInt32 compare = PL_strcmp(role.get(), nsARIAMap::gWAIRoleMap[index].roleString);
|
2008-10-16 02:12:05 -07:00
|
|
|
if (compare == 0) {
|
|
|
|
// The role attribute maps to an entry in the role table
|
|
|
|
return &nsARIAMap::gWAIRoleMap[index];
|
|
|
|
}
|
|
|
|
if (compare < 0) {
|
2009-06-30 14:29:54 -07:00
|
|
|
high = index;
|
2008-10-16 02:12:05 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = index + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-31 06:12:08 -07:00
|
|
|
// Always use some entry if there is a non-empty role string
|
2008-10-16 02:12:05 -07:00
|
|
|
// To ensure an accessible object is created
|
|
|
|
return &nsARIAMap::gLandmarkRoleMap;
|
|
|
|
}
|
2008-10-17 03:10:43 -07:00
|
|
|
|
2009-02-15 00:15:31 -08:00
|
|
|
PRUint8
|
|
|
|
nsAccUtils::GetAttributeCharacteristics(nsIAtom* aAtom)
|
|
|
|
{
|
|
|
|
for (PRUint32 i = 0; i < nsARIAMap::gWAIUnivAttrMapLength; i++)
|
|
|
|
if (*nsARIAMap::gWAIUnivAttrMap[i].attributeName == aAtom)
|
|
|
|
return nsARIAMap::gWAIUnivAttrMap[i].characteristics;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-08-27 22:27:27 -07:00
|
|
|
PRBool
|
2009-02-18 22:56:19 -08:00
|
|
|
nsAccUtils::GetLiveAttrValue(PRUint32 aRule, nsAString& aValue)
|
|
|
|
{
|
|
|
|
switch (aRule) {
|
|
|
|
case eOffLiveAttr:
|
|
|
|
aValue = NS_LITERAL_STRING("off");
|
2009-08-27 22:27:27 -07:00
|
|
|
return PR_TRUE;
|
2009-02-18 22:56:19 -08:00
|
|
|
case ePoliteLiveAttr:
|
|
|
|
aValue = NS_LITERAL_STRING("polite");
|
2009-08-27 22:27:27 -07:00
|
|
|
return PR_TRUE;
|
2009-02-18 22:56:19 -08:00
|
|
|
}
|
2009-08-27 22:27:27 -07:00
|
|
|
|
|
|
|
return PR_FALSE;
|
2009-02-18 22:56:19 -08:00
|
|
|
}
|
2008-10-17 03:10:43 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG_A11Y
|
|
|
|
|
|
|
|
PRBool
|
2010-05-18 07:03:56 -07:00
|
|
|
nsAccUtils::IsTextInterfaceSupportCorrect(nsAccessible *aAccessible)
|
2008-10-17 03:10:43 -07:00
|
|
|
{
|
|
|
|
PRBool foundText = PR_FALSE;
|
|
|
|
|
2010-05-18 07:03:56 -07:00
|
|
|
nsCOMPtr<nsIAccessibleDocument> accDoc = do_QueryObject(aAccessible);
|
2008-10-17 03:10:43 -07:00
|
|
|
if (accDoc) {
|
|
|
|
// Don't test for accessible docs, it makes us create accessibles too
|
|
|
|
// early and fire mutation events before we need to
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-05-18 07:03:56 -07:00
|
|
|
PRInt32 childCount = aAccessible->GetChildCount();
|
|
|
|
for (PRint32 childIdx = 0; childIdx < childCount; childIdx++) {
|
|
|
|
nsAccessible *child = GetChildAt(childIdx);
|
2008-10-17 03:10:43 -07:00
|
|
|
if (IsText(child)) {
|
|
|
|
foundText = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundText) {
|
|
|
|
// found text child node
|
2010-05-18 07:03:56 -07:00
|
|
|
nsCOMPtr<nsIAccessibleText> text = do_QueryObject(aAccessible);
|
2008-10-17 03:10:43 -07:00
|
|
|
if (!text)
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-05-25 01:40:54 -07:00
|
|
|
PRUint32
|
|
|
|
nsAccUtils::TextLength(nsAccessible *aAccessible)
|
2008-10-17 03:10:43 -07:00
|
|
|
{
|
|
|
|
if (!IsText(aAccessible))
|
|
|
|
return 1;
|
2010-05-25 01:40:54 -07:00
|
|
|
|
2011-01-31 19:00:45 -08:00
|
|
|
nsTextAccessible* textLeaf = aAccessible->AsTextLeaf();
|
|
|
|
if (textLeaf)
|
|
|
|
return textLeaf->Text().Length();
|
2010-05-25 01:40:54 -07:00
|
|
|
|
2008-10-17 03:10:43 -07:00
|
|
|
// For list bullets (or anything other accessible which would compute its own
|
|
|
|
// text. They don't have their own frame.
|
|
|
|
// XXX In the future, list bullets may have frame and anon content, so
|
|
|
|
// we should be able to remove this at that point
|
|
|
|
nsAutoString text;
|
2011-01-31 19:00:24 -08:00
|
|
|
aAccessible->AppendTextTo(text); // Get all the text
|
2008-10-17 03:10:43 -07:00
|
|
|
return text.Length();
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsAccUtils::MustPrune(nsIAccessible *aAccessible)
|
|
|
|
{
|
|
|
|
PRUint32 role = nsAccUtils::Role(aAccessible);
|
|
|
|
|
2009-11-09 21:58:52 -08:00
|
|
|
// We don't prune buttons any more however AT don't expect children inside of
|
|
|
|
// button in general, we allow menu buttons to have children to make them
|
|
|
|
// accessible.
|
2008-10-17 03:10:43 -07:00
|
|
|
return role == nsIAccessibleRole::ROLE_MENUITEM ||
|
|
|
|
role == nsIAccessibleRole::ROLE_COMBOBOX_OPTION ||
|
|
|
|
role == nsIAccessibleRole::ROLE_OPTION ||
|
|
|
|
role == nsIAccessibleRole::ROLE_ENTRY ||
|
|
|
|
role == nsIAccessibleRole::ROLE_FLAT_EQUATION ||
|
|
|
|
role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
|
|
|
|
role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
|
|
|
|
role == nsIAccessibleRole::ROLE_GRAPHIC ||
|
|
|
|
role == nsIAccessibleRole::ROLE_SLIDER ||
|
|
|
|
role == nsIAccessibleRole::ROLE_PROGRESSBAR ||
|
|
|
|
role == nsIAccessibleRole::ROLE_SEPARATOR;
|
|
|
|
}
|
|
|
|
|
2009-09-10 18:07:56 -07:00
|
|
|
nsresult
|
|
|
|
nsAccUtils::GetHeaderCellsFor(nsIAccessibleTable *aTable,
|
|
|
|
nsIAccessibleTableCell *aCell,
|
|
|
|
PRInt32 aRowOrColHeaderCells, nsIArray **aCells)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRInt32 rowIdx = -1;
|
|
|
|
rv = aCell->GetRowIndex(&rowIdx);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRInt32 colIdx = -1;
|
|
|
|
rv = aCell->GetColumnIndex(&colIdx);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRBool moveToLeft = aRowOrColHeaderCells == eRowHeaderCells;
|
|
|
|
|
|
|
|
// Move to the left or top to find row header cells or column header cells.
|
|
|
|
PRInt32 index = (moveToLeft ? colIdx : rowIdx) - 1;
|
|
|
|
for (; index >= 0; index--) {
|
|
|
|
PRInt32 curRowIdx = moveToLeft ? rowIdx : index;
|
|
|
|
PRInt32 curColIdx = moveToLeft ? index : colIdx;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessible> cell;
|
|
|
|
rv = aTable->GetCellAt(curRowIdx, curColIdx, getter_AddRefs(cell));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessibleTableCell> tableCellAcc =
|
|
|
|
do_QueryInterface(cell);
|
|
|
|
|
2010-08-24 06:38:31 -07:00
|
|
|
// GetCellAt should always return an nsIAccessibleTableCell (XXX Bug 587529)
|
|
|
|
NS_ENSURE_STATE(tableCellAcc);
|
|
|
|
|
2009-09-10 18:07:56 -07:00
|
|
|
PRInt32 origIdx = 1;
|
|
|
|
if (moveToLeft)
|
|
|
|
rv = tableCellAcc->GetColumnIndex(&origIdx);
|
|
|
|
else
|
|
|
|
rv = tableCellAcc->GetRowIndex(&origIdx);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (origIdx == index) {
|
|
|
|
// Append original header cells only.
|
|
|
|
PRUint32 role = Role(cell);
|
|
|
|
PRBool isHeader = moveToLeft ?
|
|
|
|
role == nsIAccessibleRole::ROLE_ROWHEADER :
|
|
|
|
role == nsIAccessibleRole::ROLE_COLUMNHEADER;
|
|
|
|
|
|
|
|
if (isHeader)
|
|
|
|
cells->AppendElement(cell, PR_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aCells = cells);
|
|
|
|
return NS_OK;
|
|
|
|
}
|