зеркало из https://github.com/mozilla/pjs.git
Fix for bug 362365 - use anonid for relations within of world of anonymous content, patch=me, aaronlev, r=Olli.Pettay, sr=jst
This commit is contained in:
Родитель
d4c460f62d
Коммит
70047e8328
|
@ -144,6 +144,7 @@ ACCESSIBILITY_ATOM(owns, "owns")
|
|||
ACCESSIBILITY_ATOM(acceltext, "acceltext")
|
||||
ACCESSIBILITY_ATOM(accesskey, "accesskey")
|
||||
ACCESSIBILITY_ATOM(alt, "alt")
|
||||
ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
|
||||
ACCESSIBILITY_ATOM(control, "control")
|
||||
ACCESSIBILITY_ATOM(data, "data")
|
||||
ACCESSIBILITY_ATOM(disabled, "disabled")
|
||||
|
|
|
@ -318,7 +318,9 @@ NS_IMETHODIMP nsAccessible::GetDescription(nsAString& aDescription)
|
|||
if (isXUL) {
|
||||
// Try XUL <description control="[id]">description text</description>
|
||||
nsIContent *descriptionContent =
|
||||
GetXULLabelContent(content, nsAccessibilityAtoms::description);
|
||||
FindNeighbourPointingToNode(content, nsAccessibilityAtoms::description,
|
||||
nsAccessibilityAtoms::control);
|
||||
|
||||
if (descriptionContent) {
|
||||
// We have a description content node
|
||||
AppendFlatStringFromSubtree(descriptionContent, &description);
|
||||
|
@ -1558,44 +1560,24 @@ nsresult nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
|
|||
|
||||
nsIContent *nsAccessible::GetLabelContent(nsIContent *aForNode)
|
||||
{
|
||||
return aForNode->IsNodeOfType(nsINode::eXUL) ? GetXULLabelContent(aForNode) :
|
||||
GetHTMLLabelContent(aForNode);
|
||||
}
|
||||
|
||||
nsIContent* nsAccessible::GetXULLabelContent(nsIContent *aForNode, nsIAtom *aLabelType)
|
||||
{
|
||||
nsAutoString controlID;
|
||||
aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::id, controlID);
|
||||
if (controlID.IsEmpty())
|
||||
return nsnull;
|
||||
if (aForNode->IsNodeOfType(nsINode::eXUL))
|
||||
return FindNeighbourPointingToNode(aForNode, nsAccessibilityAtoms::label,
|
||||
nsAccessibilityAtoms::control);
|
||||
|
||||
// Look for label in subtrees of nearby ancestors
|
||||
static const PRUint32 kAncestorLevelsToSearch = 5;
|
||||
PRUint32 count = 0;
|
||||
nsIContent *labelContent = nsnull;
|
||||
nsIContent *prevSearched = nsnull;
|
||||
|
||||
while (!labelContent && ++count <= kAncestorLevelsToSearch &&
|
||||
(aForNode = aForNode->GetParent()) != nsnull) {
|
||||
labelContent = GetContentPointingTo(&controlID, aForNode,
|
||||
nsAccessibilityAtoms::control,
|
||||
prevSearched,
|
||||
kNameSpaceID_None, aLabelType);
|
||||
prevSearched = aForNode;
|
||||
}
|
||||
|
||||
return labelContent;
|
||||
return GetHTMLLabelContent(aForNode);
|
||||
}
|
||||
|
||||
nsIContent* nsAccessible::GetHTMLLabelContent(nsIContent *aForNode)
|
||||
{
|
||||
// Get either <label for="[id]"> element which explictly points to aForNode, or
|
||||
// <label> ancestor which implicitly point to it
|
||||
nsIContent *walkUpContent = aForNode;
|
||||
|
||||
// go up tree get name of ancestor label if there is one. Don't go up farther than form element
|
||||
while ((walkUpContent = walkUpContent->GetParent()) != nsnull) {
|
||||
nsIAtom *tag = walkUpContent->Tag();
|
||||
if (tag == nsAccessibilityAtoms::label) {
|
||||
return walkUpContent;
|
||||
return walkUpContent; // An ancestor <label> implicitly points to us
|
||||
}
|
||||
if (tag == nsAccessibilityAtoms::form ||
|
||||
tag == nsAccessibilityAtoms::body) {
|
||||
|
@ -1609,7 +1591,8 @@ nsIContent* nsAccessible::GetHTMLLabelContent(nsIContent *aForNode)
|
|||
if (forId.IsEmpty()) {
|
||||
break;
|
||||
}
|
||||
return GetContentPointingTo(&forId, walkUpContent, nsAccessibilityAtoms::_for);
|
||||
return FindDescendantPointingToID(&forId, walkUpContent,
|
||||
nsAccessibilityAtoms::_for);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1667,13 +1650,88 @@ nsresult nsAccessible::GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsAccessible::FindNeighbourPointingToNode(nsIContent *aForNode,
|
||||
nsIAtom *aTagName, nsIAtom *aAttr,
|
||||
PRUint32 aAncestorLevelsToSearch)
|
||||
{
|
||||
nsCOMPtr<nsIContent> binding;
|
||||
|
||||
nsAutoString controlID;
|
||||
aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::id, controlID);
|
||||
if (controlID.IsEmpty()) {
|
||||
binding = aForNode->GetBindingParent();
|
||||
if (binding == aForNode)
|
||||
return nsnull;
|
||||
|
||||
aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID);
|
||||
if (controlID.IsEmpty())
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Look for label in subtrees of nearby ancestors
|
||||
PRUint32 count = 0;
|
||||
nsIContent *labelContent = nsnull;
|
||||
nsIContent *prevSearched = nsnull;
|
||||
|
||||
while (!labelContent && ++count <= aAncestorLevelsToSearch &&
|
||||
(aForNode = aForNode->GetParent()) != nsnull) {
|
||||
|
||||
if (aForNode == binding) {
|
||||
// When we reach the binding parent, make sure to check
|
||||
// all of its anonymous child subtrees
|
||||
nsCOMPtr<nsIDocument> doc = aForNode->GetCurrentDoc();
|
||||
nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(doc));
|
||||
if (!xblDoc)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMNodeList> nodes;
|
||||
nsCOMPtr<nsIDOMElement> forElm(do_QueryInterface(aForNode));
|
||||
xblDoc->GetAnonymousNodes(forElm, getter_AddRefs(nodes));
|
||||
if (!nodes)
|
||||
return nsnull;
|
||||
|
||||
PRUint32 length;
|
||||
nsresult rv = nodes->GetLength(&length);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
for (PRUint32 index = 0; index < length && !labelContent; index++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
rv = nodes->Item(index, getter_AddRefs(node));
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
if (!content)
|
||||
return nsnull;
|
||||
|
||||
if (content != prevSearched) {
|
||||
labelContent = FindDescendantPointingToID(&controlID, content, aAttr,
|
||||
nsnull, kNameSpaceID_None,
|
||||
aTagName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
labelContent = FindDescendantPointingToID(&controlID, aForNode,
|
||||
aAttr, prevSearched,
|
||||
kNameSpaceID_None, aTagName);
|
||||
prevSearched = aForNode;
|
||||
}
|
||||
|
||||
return labelContent;
|
||||
}
|
||||
|
||||
// Pass in aForAttrib == nsnull if any <label> will do
|
||||
nsIContent *nsAccessible::GetContentPointingTo(const nsAString *aId,
|
||||
nsIContent *aLookContent,
|
||||
nsIAtom *aForAttrib,
|
||||
nsIContent *aExcludeContent,
|
||||
PRUint32 aForAttribNameSpace,
|
||||
nsIAtom *aTagType)
|
||||
nsIContent*
|
||||
nsAccessible::FindDescendantPointingToID(const nsAString *aId,
|
||||
nsIContent *aLookContent,
|
||||
nsIAtom *aForAttrib,
|
||||
nsIContent *aExcludeContent,
|
||||
PRUint32 aForAttribNameSpace,
|
||||
nsIAtom *aTagType)
|
||||
{
|
||||
if (!aTagType || aLookContent->Tag() == aTagType) {
|
||||
if (aForAttrib) {
|
||||
|
@ -1698,15 +1756,16 @@ nsIContent *nsAccessible::GetContentPointingTo(const nsAString *aId,
|
|||
}
|
||||
}
|
||||
|
||||
// Recursively search descendents for labels
|
||||
// Recursively search descendants for labels
|
||||
PRUint32 count = 0;
|
||||
nsIContent *child;
|
||||
nsIContent *labelContent = nsnull;
|
||||
|
||||
while ((child = aLookContent->GetChildAt(count++)) != nsnull) {
|
||||
if (child != aExcludeContent) {
|
||||
labelContent = GetContentPointingTo(aId, child, aForAttrib, aExcludeContent,
|
||||
aForAttribNameSpace, aTagType);
|
||||
labelContent = FindDescendantPointingToID(aId, child, aForAttrib,
|
||||
aExcludeContent,
|
||||
aForAttribNameSpace, aTagType);
|
||||
}
|
||||
if (labelContent) {
|
||||
return labelContent;
|
||||
|
@ -1812,7 +1871,10 @@ nsresult nsAccessible::GetXULName(nsAString& aLabel, PRBool aCanAggregateSubtree
|
|||
// CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
|
||||
if (NS_FAILED(rv) || label.IsEmpty()) {
|
||||
label.Truncate();
|
||||
nsIContent *labelContent = GetXULLabelContent(content);
|
||||
nsIContent *labelContent =
|
||||
FindNeighbourPointingToNode(content, nsAccessibilityAtoms::label,
|
||||
nsAccessibilityAtoms::control);
|
||||
|
||||
nsCOMPtr<nsIDOMXULLabelElement> xulLabel(do_QueryInterface(labelContent));
|
||||
// Check if label's value attribute is used
|
||||
if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(label)) && label.IsEmpty()) {
|
||||
|
@ -2358,39 +2420,24 @@ NS_IMETHODIMP nsAccessible::GetAccessibleBelow(nsIAccessible **_retval)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMNode> nsAccessible::GetInverseRelatedNode(nsIAtom *aRelationAttr,
|
||||
PRUint32 aAncestorLevelsToSearch)
|
||||
already_AddRefed<nsIDOMNode>
|
||||
nsAccessible::FindNeighbourPointingToThis(nsIAtom *aRelationAttr,
|
||||
PRUint32 aAncestorLevelsToSearch)
|
||||
{
|
||||
// aAncestorLevelsToSearch is an optimization used for label and description searches.
|
||||
// We expect the control to be relatively near the label/description in the DOM tree,
|
||||
// so to optimize we don't search the entire DOM tree.
|
||||
nsIContent *content = GetRoleContent(mDOMNode);
|
||||
if (!content) {
|
||||
if (!content)
|
||||
return nsnull; // Node shut down
|
||||
}
|
||||
nsAutoString controlID;
|
||||
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::id, controlID);
|
||||
if (controlID.IsEmpty()) {
|
||||
|
||||
nsIContent* description = FindNeighbourPointingToNode(content, nsnull,
|
||||
aRelationAttr,
|
||||
aAncestorLevelsToSearch);
|
||||
|
||||
if (!description)
|
||||
return nsnull;
|
||||
}
|
||||
// Something might be pointing to us
|
||||
PRUint32 count = 0;
|
||||
nsIContent *start = content;
|
||||
nsIContent *prevSearched = nsnull;
|
||||
while ((!aAncestorLevelsToSearch || ++count <= aAncestorLevelsToSearch) &&
|
||||
(start = start->GetParent()) != nsnull) {
|
||||
nsIContent *description = GetContentPointingTo(&controlID, start,
|
||||
aRelationAttr, prevSearched,
|
||||
kNameSpaceID_WAIProperties,
|
||||
nsnull);
|
||||
if (description) {
|
||||
nsIDOMNode *relatedNode;
|
||||
CallQueryInterface(description, &relatedNode);
|
||||
return relatedNode;
|
||||
}
|
||||
prevSearched = start;
|
||||
}
|
||||
return nsnull;
|
||||
|
||||
nsIDOMNode *relatedNode;
|
||||
CallQueryInterface(description, &relatedNode);
|
||||
return relatedNode;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2423,7 +2470,8 @@ NS_IMETHODIMP nsAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAcce
|
|||
}
|
||||
if (relatedID.IsEmpty()) {
|
||||
const PRUint32 kAncestorLevelsToSearch = 3;
|
||||
relatedNode = GetInverseRelatedNode(nsAccessibilityAtoms::labelledby, kAncestorLevelsToSearch);
|
||||
relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::labelledby,
|
||||
kAncestorLevelsToSearch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2442,7 +2490,10 @@ NS_IMETHODIMP nsAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAcce
|
|||
nsAccessibilityAtoms::describedby, relatedID);
|
||||
if (relatedID.IsEmpty()) {
|
||||
nsIContent *description =
|
||||
GetXULLabelContent(content, nsAccessibilityAtoms::description);
|
||||
FindNeighbourPointingToNode(content,
|
||||
nsAccessibilityAtoms::description,
|
||||
nsAccessibilityAtoms::control);
|
||||
|
||||
relatedNode = do_QueryInterface(description);
|
||||
}
|
||||
break;
|
||||
|
@ -2450,7 +2501,10 @@ NS_IMETHODIMP nsAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAcce
|
|||
case RELATION_DESCRIPTION_FOR:
|
||||
{
|
||||
const PRUint32 kAncestorLevelsToSearch = 3;
|
||||
relatedNode = GetInverseRelatedNode(nsAccessibilityAtoms::describedby, kAncestorLevelsToSearch);
|
||||
relatedNode =
|
||||
FindNeighbourPointingToThis(nsAccessibilityAtoms::describedby,
|
||||
kAncestorLevelsToSearch);
|
||||
|
||||
if (!relatedNode && content->Tag() == nsAccessibilityAtoms::description &&
|
||||
content->IsNodeOfType(nsINode::eXUL)) {
|
||||
// This affectively adds an optional control attribute to xul:description,
|
||||
|
@ -2461,14 +2515,14 @@ NS_IMETHODIMP nsAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAcce
|
|||
}
|
||||
break;
|
||||
}
|
||||
case RELATION_NODE_CHILD_OF:
|
||||
case RELATION_NODE_CHILD_OF:
|
||||
{
|
||||
relatedNode = GetInverseRelatedNode(nsAccessibilityAtoms::owns);
|
||||
relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::owns);
|
||||
break;
|
||||
}
|
||||
case RELATION_CONTROLLED_BY:
|
||||
case RELATION_CONTROLLED_BY:
|
||||
{
|
||||
relatedNode = GetInverseRelatedNode(nsAccessibilityAtoms::controls);
|
||||
relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::controls);
|
||||
break;
|
||||
}
|
||||
case RELATION_CONTROLLER_FOR:
|
||||
|
@ -2485,7 +2539,7 @@ NS_IMETHODIMP nsAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAcce
|
|||
}
|
||||
case RELATION_FLOWS_FROM:
|
||||
{
|
||||
relatedNode = GetInverseRelatedNode(nsAccessibilityAtoms::flowto);
|
||||
relatedNode = FindNeighbourPointingToThis(nsAccessibilityAtoms::flowto);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -187,20 +187,54 @@ protected:
|
|||
virtual nsIFrame* GetBoundsFrame();
|
||||
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
|
||||
PRBool IsVisible(PRBool *aIsOffscreen);
|
||||
nsresult GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName);
|
||||
|
||||
static nsIContent *GetContentPointingTo(const nsAString *aId,
|
||||
nsIContent *aLookContent,
|
||||
nsIAtom *forAttrib,
|
||||
nsIContent *aExcludeContent = nsnull,
|
||||
PRUint32 aForAttribNamespace = kNameSpaceID_None,
|
||||
nsIAtom *aTagType = nsAccessibilityAtoms::label);
|
||||
static nsIContent *GetXULLabelContent(nsIContent *aForNode,
|
||||
nsIAtom *aLabelType = nsAccessibilityAtoms::label);
|
||||
// Relation helpers
|
||||
nsresult GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName);
|
||||
already_AddRefed<nsIDOMNode> FindNeighbourPointingToThis(nsIAtom *aRelationAttr,
|
||||
PRUint32 aAncestorLevelsToSearch = 0);
|
||||
|
||||
/**
|
||||
* Search element in neighborhood of the given element by tag name and
|
||||
* 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.
|
||||
*
|
||||
* @param aForNode - the given element the search is performed for
|
||||
* @param aTagName - tag name of searched element
|
||||
* @param aAttr - attribute name of searched element
|
||||
* @param aAncestorLevelsToSearch - points how is the neighborhood of the
|
||||
* given element big.
|
||||
*/
|
||||
static nsIContent *FindNeighbourPointingToNode(nsIContent *aForNode,
|
||||
nsIAtom *aTagName,
|
||||
nsIAtom *aAttr,
|
||||
PRUint32 aAncestorLevelsToSearch = 5);
|
||||
|
||||
/**
|
||||
* Search for element that satisfies the requirements in subtree of the given
|
||||
* element. The requirements are tag name, attribute name and value of
|
||||
* attribute.
|
||||
*
|
||||
* @param aId - value of searched attribute
|
||||
* @param aLookContent - element that search is performed inside
|
||||
* @param aForAttrib - searched attribute
|
||||
* @param aExcludeContent - element that is skiped for search
|
||||
* @param aForAttribNamespace - namespace id of searched attribute, by default
|
||||
* empty namespace
|
||||
* @param aTagType - tag name of searched element, by default it is 'label'
|
||||
*/
|
||||
static nsIContent *FindDescendantPointingToID(const nsAString *aId,
|
||||
nsIContent *aLookContent,
|
||||
nsIAtom *forAttrib,
|
||||
nsIContent *aExcludeContent = nsnull,
|
||||
PRUint32 aForAttribNamespace = kNameSpaceID_None,
|
||||
nsIAtom *aTagType = nsAccessibilityAtoms::label);
|
||||
|
||||
static nsIContent *GetHTMLLabelContent(nsIContent *aForNode);
|
||||
static nsIContent *GetLabelContent(nsIContent *aForNode);
|
||||
static nsIContent *GetRoleContent(nsIDOMNode *aDOMNode);
|
||||
|
||||
// Name helpers
|
||||
nsresult GetHTMLName(nsAString& _retval, PRBool aCanAggregateSubtree = PR_TRUE);
|
||||
nsresult GetXULName(nsAString& aName, PRBool aCanAggregateSubtree = PR_TRUE);
|
||||
// For accessibles that are not lists of choices, the name of the subtree should be the
|
||||
|
@ -244,10 +278,6 @@ protected:
|
|||
static void DoCommandCallback(nsITimer *aTimer, void *aClosure);
|
||||
nsresult DoCommand(nsIContent *aContent = nsnull);
|
||||
|
||||
// Relation helpers
|
||||
already_AddRefed<nsIDOMNode> GetInverseRelatedNode(nsIAtom *aRelationAttr,
|
||||
PRUint32 aAncestorLevelsToSearch = 0);
|
||||
|
||||
// Data Members
|
||||
nsCOMPtr<nsIAccessible> mParent;
|
||||
nsIAccessible *mFirstChild, *mNextSibling;
|
||||
|
|
Загрузка…
Ссылка в новой задаче