From 16b37806bc241105d2ee7f4573e548d19f53adc4 Mon Sep 17 00:00:00 2001 From: "Evan.Yan@Sun.COM" Date: Mon, 21 Jan 2008 19:17:37 -0800 Subject: [PATCH] Bug 395699 - relations not working when pointing to a r=surkov.alexander a=mtschrep --- .../src/base/nsAccessibilityService.cpp | 31 +++++++++- accessible/src/base/nsAccessibilityUtils.cpp | 62 ++++++++++++++----- accessible/src/base/nsAccessibilityUtils.h | 36 +++++++++-- 3 files changed, 106 insertions(+), 23 deletions(-) diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index a990f438b575..9f77c6fd2ebb 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -1196,6 +1196,34 @@ nsresult nsAccessibilityService::InitAccessible(nsIAccessible *aAccessibleIn, return rv; } +static PRBool HasRelatedContent(nsIContent *aContent) +{ + nsAutoString id; + if (!aContent || !nsAccUtils::GetID(aContent, id) || id.IsEmpty()) { + return PR_FALSE; + } + + nsIAtom *relationAttrs[] = {nsAccessibilityAtoms::aria_labelledby, + nsAccessibilityAtoms::aria_describedby, + nsAccessibilityAtoms::aria_owns, + nsAccessibilityAtoms::aria_controls, + nsAccessibilityAtoms::aria_flowto}; + if (nsAccUtils::FindNeighbourPointingToNode(aContent, relationAttrs, NS_ARRAY_LENGTH(relationAttrs))) { + return PR_TRUE; + } + + nsIContent *ancestorContent = aContent; + nsAutoString activeID; + while ((ancestorContent = ancestorContent->GetParent()) != nsnull) { + if (ancestorContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant, activeID)) { + // ancestor has activedescendant property, this content could be active + return PR_TRUE; + } + } + + return PR_FALSE; +} + NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode, nsIPresShell *aPresShell, nsIWeakReference *aWeakShell, @@ -1468,7 +1496,8 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode, if (!newAcc && content->Tag() != nsAccessibilityAtoms::body && content->GetParent() && (content->IsFocusable() || (isHTML && nsAccUtils::HasListener(content, NS_LITERAL_STRING("click"))) || - HasUniversalAriaProperty(content, aWeakShell) || roleMapEntry)) { + HasUniversalAriaProperty(content, aWeakShell) || roleMapEntry) || + HasRelatedContent(content)) { // This content is focusable or has an interesting dynamic content accessibility property. // If it's interesting we need it in the accessibility hierarchy so that events or // other accessibles can point to it, or so that it can hold a state, etc. diff --git a/accessible/src/base/nsAccessibilityUtils.cpp b/accessible/src/base/nsAccessibilityUtils.cpp index 4fea01d9ef01..2bf196bc29ee 100755 --- a/accessible/src/base/nsAccessibilityUtils.cpp +++ b/accessible/src/base/nsAccessibilityUtils.cpp @@ -586,6 +586,16 @@ nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode, nsIAtom *aRelationAttr, nsIAtom *aTagName, PRUint32 aAncestorLevelsToSearch) +{ + return FindNeighbourPointingToNode(aForNode, &aRelationAttr, 1, aTagName, aAncestorLevelsToSearch); +} + +nsIContent* +nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode, + nsIAtom **aRelationAttrs, + PRUint32 aAttrNum, + nsIAtom *aTagName, + PRUint32 aAncestorLevelsToSearch) { nsCOMPtr binding; nsAutoString controlID; @@ -638,14 +648,16 @@ nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode, if (content != prevSearched) { labelContent = FindDescendantPointingToID(&controlID, content, - aRelationAttr, nsnull, aTagName); + aRelationAttrs, aAttrNum, + nsnull, aTagName); } } break; } labelContent = FindDescendantPointingToID(&controlID, aForNode, - aRelationAttr, prevSearched, aTagName); + aRelationAttrs, aAttrNum, + prevSearched, aTagName); prevSearched = aForNode; } @@ -656,7 +668,8 @@ nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode, nsIContent* nsAccUtils::FindDescendantPointingToID(const nsString *aId, nsIContent *aLookContent, - nsIAtom *aRelationAttr, + nsIAtom **aRelationAttrs, + PRUint32 aAttrNum, nsIContent *aExcludeContent, nsIAtom *aTagType) { @@ -665,31 +678,45 @@ nsAccUtils::FindDescendantPointingToID(const nsString *aId, LossyAppendUTF16toASCII(*aId, idWithSpaces); idWithSpaces += ' '; return FindDescendantPointingToIDImpl(idWithSpaces, aLookContent, - aRelationAttr, aExcludeContent, aTagType); + aRelationAttrs, aAttrNum, + aExcludeContent, aTagType); +} + +nsIContent* +nsAccUtils::FindDescendantPointingToID(const nsString *aId, + nsIContent *aLookContent, + nsIAtom *aRelationAttr, + nsIContent *aExcludeContent, + nsIAtom *aTagType) +{ + return FindDescendantPointingToID(aId, aLookContent, &aRelationAttr, 1, aExcludeContent, aTagType); } nsIContent* nsAccUtils::FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces, nsIContent *aLookContent, - nsIAtom *aRelationAttr, + nsIAtom **aRelationAttrs, + PRUint32 aAttrNum, nsIContent *aExcludeContent, nsIAtom *aTagType) { NS_ENSURE_TRUE(aLookContent, nsnull); - NS_ENSURE_TRUE(aRelationAttr, nsnull); + NS_ENSURE_TRUE(aRelationAttrs && *aRelationAttrs, nsnull); if (!aTagType || aLookContent->Tag() == aTagType) { // Tag matches - // Check for ID in the attribute aRelationAttr, which can be a list - nsAutoString idList; - if (aLookContent->GetAttr(kNameSpaceID_None, aRelationAttr, idList)) { - idList.Insert(' ', 0); // Surround idlist with spaces for search - idList.Append(' '); - // idList is now a set of id's with spaces around each, - // and id also has spaces around it. - // If id is a substring of idList then we have a match - if (idList.Find(aIdWithSpaces) != -1) { - return aLookContent; + // Check for ID in the attributes aRelationAttrs, which can be a list + for (PRUint32 i = 0; i < aAttrNum; i++) { + nsAutoString idList; + if (aLookContent->GetAttr(kNameSpaceID_None, aRelationAttrs[i], idList)) { + idList.Insert(' ', 0); // Surround idlist with spaces for search + idList.Append(' '); + // idList is now a set of id's with spaces around each, + // and id also has spaces around it. + // If id is a substring of idList then we have a match + if (idList.Find(aIdWithSpaces) != -1) { + return aLookContent; + } } } if (aTagType) { @@ -707,7 +734,8 @@ nsAccUtils::FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces, while ((child = aLookContent->GetChildAt(count++)) != nsnull) { if (child != aExcludeContent) { labelContent = FindDescendantPointingToIDImpl(aIdWithSpaces, child, - aRelationAttr, aExcludeContent, aTagType); + aRelationAttrs, aAttrNum, + aExcludeContent, aTagType); if (labelContent) { return labelContent; } diff --git a/accessible/src/base/nsAccessibilityUtils.h b/accessible/src/base/nsAccessibilityUtils.h index 55c48d673f2b..963f75b6b734 100755 --- a/accessible/src/base/nsAccessibilityUtils.h +++ b/accessible/src/base/nsAccessibilityUtils.h @@ -277,15 +277,27 @@ public: * attribute value that equals to ID attribute of the given element. * ID attribute can be either 'id' attribute or 'anonid' if the element is * anonymous. + * The first matched content will be returned. * * @param aForNode - the given element the search is performed for - * @param aRelationAttr - attribute name of searched element, ignored if aAriaProperty passed in + * @param aRelationAttrs - an array of attributes, element is attribute name of searched element, ignored if aAriaProperty passed in + * @param aAttrNum - how many attributes in aRelationAttrs * @param aTagName - tag name of searched element, or nsnull for any -- ignored if aAriaProperty passed in * @param aAncestorLevelsToSearch - points how is the neighborhood of the * given element big. */ static nsIContent *FindNeighbourPointingToNode(nsIContent *aForNode, - nsIAtom *aRelationAttr, + nsIAtom **aRelationAttrs, + PRUint32 aAttrNum, + nsIAtom *aTagName = nsnull, + PRUint32 aAncestorLevelsToSearch = 5); + + /** + * Overloaded version of FindNeighbourPointingToNode to accept only one + * relation attribute. + */ + static nsIContent *FindNeighbourPointingToNode(nsIContent *aForNode, + nsIAtom *aRelationAttr, nsIAtom *aTagName = nsnull, PRUint32 aAncestorLevelsToSearch = 5); @@ -293,15 +305,28 @@ public: * Search for element that satisfies the requirements in subtree of the given * element. The requirements are tag name, attribute name and value of * attribute. + * The first matched content will be returned. * * @param aId - value of searched attribute * @param aLookContent - element that search is performed inside - * @param aRelationAttr - searched attribute - * @param if both aAriaProperty and aRelationAttr are null, then any element with aTagType will do + * @param aRelationAttrs - an array of searched attributes + * @param aAttrNum - how many attributes in aRelationAttrs + * @param if both aAriaProperty and aRelationAttrs are null, then any element with aTagType will do * @param aExcludeContent - element that is skiped for search * @param aTagType - tag name of searched element, by default it is 'label' -- * ignored if aAriaProperty passed in */ + static nsIContent *FindDescendantPointingToID(const nsString *aId, + nsIContent *aLookContent, + nsIAtom **aRelationAttrs, + PRUint32 aAttrNum = 1, + nsIContent *aExcludeContent = nsnull, + nsIAtom *aTagType = nsAccessibilityAtoms::label); + + /** + * Overloaded version of FindDescendantPointingToID to accept only one + * relation attribute. + */ static nsIContent *FindDescendantPointingToID(const nsString *aId, nsIContent *aLookContent, nsIAtom *aRelationAttr, @@ -311,7 +336,8 @@ public: // Helper for FindDescendantPointingToID(), same args static nsIContent *FindDescendantPointingToIDImpl(nsCString& aIdWithSpaces, nsIContent *aLookContent, - nsIAtom *aRelationAttrs, + nsIAtom **aRelationAttrs, + PRUint32 aAttrNum = 1, nsIContent *aExcludeContent = nsnull, nsIAtom *aTagType = nsAccessibilityAtoms::label); };