diff --git a/accessible/src/base/nsAccessibilityAtomList.h b/accessible/src/base/nsAccessibilityAtomList.h index 8add029d65c4..72d9f61e9cad 100755 --- a/accessible/src/base/nsAccessibilityAtomList.h +++ b/accessible/src/base/nsAccessibilityAtomList.h @@ -109,6 +109,7 @@ ACCESSIBILITY_ATOM(itemset, "itemset") // XForms ACCESSIBILITY_ATOM(img, "img") ACCESSIBILITY_ATOM(input, "input") ACCESSIBILITY_ATOM(label, "label") +ACCESSIBILITY_ATOM(legend, "legend") ACCESSIBILITY_ATOM(li, "li") ACCESSIBILITY_ATOM(link, "link") ACCESSIBILITY_ATOM(map, "map") diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 84206c5c9943..2b1b8eabe7d3 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -454,7 +454,10 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame *aFrame, *aAccessible = nsnull; nsCOMPtr content(do_QueryInterface(aNode)); nsIAtom *tag = content->Tag(); - if (tag == nsAccessibilityAtoms::option) { + if (tag == nsAccessibilityAtoms::legend) { + *aAccessible = new nsHTMLLegendAccessible(aNode, aWeakShell); + } + else if (tag == nsAccessibilityAtoms::option) { *aAccessible = new nsHTMLSelectOptionAccessible(aNode, aWeakShell); } else if (tag == nsAccessibilityAtoms::optgroup) { diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index e7e28778559d..b7177d888cb7 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -2722,9 +2722,9 @@ NS_IMETHODIMP nsAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAcce if (relatedNode) { nsCOMPtr accService = GetAccService(); NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE); - return accService->GetAccessibleInWeakShell(relatedNode, mWeakShell, aRelated); + accService->GetAccessibleInWeakShell(relatedNode, mWeakShell, aRelated); } - return NS_ERROR_FAILURE; + return NS_OK; } NS_IMETHODIMP diff --git a/accessible/src/html/nsHTMLFormControlAccessible.cpp b/accessible/src/html/nsHTMLFormControlAccessible.cpp index 9450bfacdeeb..13009eada1a3 100644 --- a/accessible/src/html/nsHTMLFormControlAccessible.cpp +++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp @@ -572,7 +572,7 @@ void nsHTMLTextFieldAccessible::CheckForEditor() */ nsHTMLGroupboxAccessible::nsHTMLGroupboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell): -nsAccessibleWrap(aNode, aShell) +nsHyperTextAccessibleWrap(aNode, aShell) { } @@ -582,19 +582,30 @@ NS_IMETHODIMP nsHTMLGroupboxAccessible::GetRole(PRUint32 *_retval) return NS_OK; } -NS_IMETHODIMP -nsHTMLGroupboxAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState) +nsIContent* nsHTMLGroupboxAccessible::GetLegend() { - // Groupbox doesn't support any states! - *aState = 0; - if (aExtraState) - *aExtraState = 0; + nsCOMPtr content = do_QueryInterface(mDOMNode); + NS_ENSURE_TRUE(content, nsnull); - return NS_OK; + nsresult count = 0; + nsIContent *testLegendContent; + while ((testLegendContent = content->GetChildAt(count ++ )) != nsnull) { + if (testLegendContent->NodeInfo()->Equals(nsAccessibilityAtoms::legend, + content->GetNameSpaceID())) { + // Either XHTML namespace or no namespace + return testLegendContent; + } + } + + return nsnull; } NS_IMETHODIMP nsHTMLGroupboxAccessible::GetName(nsAString& aName) { + if (!mDOMNode) { + return NS_ERROR_FAILURE; + } + aName.Truncate(); if (mRoleMapEntry) { nsAccessible::GetName(aName); if (!aName.IsEmpty()) { @@ -602,59 +613,77 @@ NS_IMETHODIMP nsHTMLGroupboxAccessible::GetName(nsAString& aName) } } - nsCOMPtr element(do_QueryInterface(mDOMNode)); - if (element) { - nsCOMPtr legends; - nsAutoString nameSpaceURI; - element->GetNamespaceURI(nameSpaceURI); - element->GetElementsByTagNameNS(nameSpaceURI, NS_LITERAL_STRING("legend"), - getter_AddRefs(legends)); - if (legends) { - nsCOMPtr legendNode; - legends->Item(0, getter_AddRefs(legendNode)); - nsCOMPtr legendContent(do_QueryInterface(legendNode)); - if (legendContent) { - aName.Truncate(); // Default name is blank - return AppendFlatStringFromSubtree(legendContent, &aName); - } - } + nsIContent *legendContent = GetLegend(); + if (legendContent) { + return AppendFlatStringFromSubtree(legendContent, &aName); } + return NS_OK; } -void nsHTMLGroupboxAccessible::CacheChildren() +NS_IMETHODIMP +nsHTMLGroupboxAccessible::GetAccessibleRelated(PRUint32 aRelationType, + nsIAccessible **aRelated) { - if (!mWeakShell) { - // This node has been shut down - mAccChildCount = eChildCountUninitialized; - return; + if (!mDOMNode) { + return NS_ERROR_FAILURE; + } + NS_ENSURE_ARG_POINTER(aRelated, NS_ERROR_NULL_POINTER); + + *aRelated = nsnull; + + nsresult rv = nsHyperTextAccessibleWrap::GetAccessibleRelated(aRelationType, aRelated); + if (NS_FAILED(rv) || *aRelated) { + // Either the node is shut down, or another relation mechanism has been used + return rv; } - if (mAccChildCount == eChildCountUninitialized) { - PRBool allowsAnonChildren = PR_FALSE; - GetAllowsAnonChildAccessibles(&allowsAnonChildren); - nsAccessibleTreeWalker walker(mWeakShell, mDOMNode, allowsAnonChildren); - walker.mState.frame = GetFrame(); - PRInt32 childCount = 0; - walker.GetFirstChild(); - // Check for and skip it if it's there - if (walker.mState.accessible && walker.mState.domNode) { - nsCOMPtr mightBeLegendNode; - walker.mState.domNode->GetParentNode(getter_AddRefs(mightBeLegendNode)); - nsCOMPtr legend(do_QueryInterface(mightBeLegendNode)); - if (legend) { - walker.GetNextSibling(); // Skip the legend + if (aRelationType == nsIAccessibleRelation::RELATION_LABELLED_BY) { + // No override for label, so use for this
+ nsCOMPtr legendNode = do_QueryInterface(GetLegend()); + if (legendNode) { + GetAccService()->GetAccessibleInWeakShell(legendNode, mWeakShell, aRelated); + } + } + + return NS_OK; +} + +nsHTMLLegendAccessible::nsHTMLLegendAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell): +nsHyperTextAccessibleWrap(aNode, aShell) +{ +} + +NS_IMETHODIMP +nsHTMLLegendAccessible::GetAccessibleRelated(PRUint32 aRelationType, + nsIAccessible **aRelated) +{ + *aRelated = nsnull; + + nsresult rv = nsHyperTextAccessibleWrap::GetAccessibleRelated(aRelationType, aRelated); + if (NS_FAILED(rv) || *aRelated) { + // Either the node is shut down, or another relation mechanism has been used + return rv; + } + + if (aRelationType == nsIAccessibleRelation::RELATION_LABEL_FOR) { + // Look for groupbox parent + nsCOMPtr content = do_QueryInterface(mDOMNode); + if (!content) { + return NS_ERROR_FAILURE; // Node already shut down + } + nsCOMPtr groupboxAccessible = GetParent(); + if (groupboxAccessible && + Role(groupboxAccessible) == nsIAccessibleRole::ROLE_GROUPING) { + nsCOMPtr testLabelAccessible; + groupboxAccessible->GetAccessibleRelated(nsIAccessibleRelation::RELATION_LABELLED_BY, + getter_AddRefs(testLabelAccessible)); + if (testLabelAccessible == this) { + // We're the first child of the parent groupbox + NS_ADDREF(*aRelated = groupboxAccessible); } } - SetFirstChild(walker.mState.accessible); - nsCOMPtr privatePrevAccessible; - while (walker.mState.accessible) { - ++ childCount; - privatePrevAccessible = do_QueryInterface(walker.mState.accessible); - privatePrevAccessible->SetParent(this); - walker.GetNextSibling(); - privatePrevAccessible->SetNextSibling(walker.mState.accessible); - } - mAccChildCount = childCount; } + + return NS_OK; } diff --git a/accessible/src/html/nsHTMLFormControlAccessible.h b/accessible/src/html/nsHTMLFormControlAccessible.h index b8bf679216bc..09660b7edbd9 100644 --- a/accessible/src/html/nsHTMLFormControlAccessible.h +++ b/accessible/src/html/nsHTMLFormControlAccessible.h @@ -124,14 +124,23 @@ protected: nsCOMPtr mEditor; }; -class nsHTMLGroupboxAccessible : public nsAccessibleWrap +class nsHTMLGroupboxAccessible : public nsHyperTextAccessibleWrap { public: nsHTMLGroupboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell); - NS_IMETHOD GetRole(PRUint32 *_retval); - NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState); - NS_IMETHOD GetName(nsAString& _retval); - void CacheChildren(); + NS_IMETHOD GetRole(PRUint32 *aRole); + NS_IMETHOD GetName(nsAString& aName); + NS_IMETHOD GetAccessibleRelated(PRUint32 aRelationType, nsIAccessible **aRelated); +protected: + nsIContent* GetLegend(); +}; + +class nsHTMLLegendAccessible : public nsHyperTextAccessibleWrap +{ +public: + nsHTMLLegendAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell); + NS_IMETHOD GetAccessibleRelated(PRUint32 aRelationType, nsIAccessible **aRelated); + NS_IMETHOD GetRole(PRUint32 *aRole) { *aRole = nsIAccessibleRole::ROLE_LABEL; return NS_OK; } }; #endif diff --git a/accessible/src/xul/nsXULFormControlAccessible.cpp b/accessible/src/xul/nsXULFormControlAccessible.cpp index 63fe3d7a4aea..acb7b4afb0ca 100644 --- a/accessible/src/xul/nsXULFormControlAccessible.cpp +++ b/accessible/src/xul/nsXULFormControlAccessible.cpp @@ -400,51 +400,59 @@ nsAccessibleWrap(aNode, aShell) { } -NS_IMETHODIMP nsXULGroupboxAccessible::GetRole(PRUint32 *_retval) +NS_IMETHODIMP nsXULGroupboxAccessible::GetRole(PRUint32 *aRole) { - *_retval = nsIAccessibleRole::ROLE_GROUPING; + *aRole = nsIAccessibleRole::ROLE_GROUPING; return NS_OK; } NS_IMETHODIMP -nsXULGroupboxAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState) +nsXULGroupboxAccessible::GetName(nsAString& aName) { - // Groupbox doesn't support focusable state! - nsresult rv = nsAccessible::GetState(aState, aExtraState); - NS_ENSURE_SUCCESS(rv, rv); + aName.Truncate(); - *aState &= ~nsIAccessibleStates::STATE_FOCUSABLE; + nsCOMPtr label; + GetAccessibleRelated(nsIAccessibleRelation::RELATION_LABELLED_BY, + getter_AddRefs(label)); + if (label) { + return label->GetName(aName); + } return NS_OK; } -NS_IMETHODIMP nsXULGroupboxAccessible::GetName(nsAString& aName) +NS_IMETHODIMP +nsXULGroupboxAccessible::GetAccessibleRelated(PRUint32 aRelationType, + nsIAccessible **aRelated) { - aName.Truncate(); // Default name is blank + *aRelated = nsnull; - if (mRoleMapEntry) { - nsAccessible::GetName(aName); - if (!aName.IsEmpty()) { - return NS_OK; - } + nsresult rv = nsAccessibleWrap::GetAccessibleRelated(aRelationType, aRelated); + if (NS_FAILED(rv) || *aRelated) { + // Either the node is shut down, or another relation mechanism has been used + return rv; } - nsCOMPtr element(do_QueryInterface(mDOMNode)); - if (element) { - nsCOMPtr captions; - nsAutoString nameSpaceURI; - element->GetNamespaceURI(nameSpaceURI); - element->GetElementsByTagNameNS(nameSpaceURI, NS_LITERAL_STRING("caption"), - getter_AddRefs(captions)); - if (captions) { - nsCOMPtr captionNode; - captions->Item(0, getter_AddRefs(captionNode)); - if (captionNode) { - element = do_QueryInterface(captionNode); - NS_ASSERTION(element, "No nsIDOMElement for caption node!"); - element->GetAttribute(NS_LITERAL_STRING("label"), aName) ; + + if (aRelationType == nsIAccessibleRelation::RELATION_LABELLED_BY) { + // The label for xul:groupbox is generated from xul:label that is + // inside the anonymous content of the xul:caption. + // The xul:label has an accessible object but the xul:caption does not + nsCOMPtr testLabelAccessible; + while (NextChild(testLabelAccessible)) { + if (Role(testLabelAccessible) == nsIAccessibleRole::ROLE_LABEL) { + // Ensure that it's our label + nsCOMPtr testGroupboxAccessible; + testLabelAccessible->GetAccessibleRelated(nsIAccessibleRelation::RELATION_LABEL_FOR, + getter_AddRefs(testGroupboxAccessible)); + if (testGroupboxAccessible == this) { + // The