Bug 349885. GetAccessibleFor() doesn't look if ally nodes are allowed inside anon content. Patch by Alexander Surkov. r=aaronlev, sr=neil

This commit is contained in:
aaronleventhal%moonset.net 2006-10-30 02:49:34 +00:00
Родитель 77e17ead1b
Коммит 2fee238453
5 изменённых файлов: 138 добавлений и 27 удалений

Просмотреть файл

@ -54,7 +54,7 @@ interface nsIAccessNode;
*
* @status UNDER_REVIEW
*/
[scriptable, uuid(663CA4A8-D219-4000-925D-D8F66406B626)]
[scriptable, uuid(2d8c1b1b-7a3f-4962-8a88-81ca019c11e9)]
interface nsIAccessibleRetrieval : nsISupports
{
/**
@ -66,6 +66,30 @@ interface nsIAccessibleRetrieval : nsISupports
*/
nsIAccessible getAccessibleFor(in nsIDOMNode aNode);
/**
* The same like getAccessibleFor method except it returns accessible only if
* it is attached, i.e. accessible is certified to be a descendent of the root
* accessible.
*
* @param aNode - the DOM node to get an accessible for.
*
* @return - the accessible for the given DOM node.
*/
nsIAccessible getAttachedAccessibleFor(in nsIDOMNode aNode);
/**
* Return an DOM node that is relevant to attached accesible check. This
* node is either from bindings chain if given node is anonymous and owner
* binding denies accessible in anonymous content or given node (it's not
* important whether it is accessible or not). This method doesn't create
* accessible object for returned node.
*
* @param aNode - the DOM node to get relevant content node.
*
* @return - the DOM node for parent attached accessible
*/
nsIDOMNode getRelevantContentNodeFor(in nsIDOMNode aNode);
/**
* Return an nsIAccessible for a DOM node in pres shell for this DOM window.
* Create a new accessible of the appropriate type if necessary,

Просмотреть файл

@ -968,11 +968,12 @@ NS_IMETHODIMP nsAccessibilityService::GetCachedAccessNode(nsIDOMNode *aNode,
* GetAccessibleFor - get an nsIAccessible from a DOM node
*/
NS_IMETHODIMP nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
NS_IMETHODIMP
nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
{
// It's not ideal to call this -- it will assume shell #0
// Some of our old test scripts still use it
// We use presentation shell #0 because we assume that is presentation of
// given node window.
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
nsCOMPtr<nsIDocument> doc;
if (content) {
@ -988,6 +989,25 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
return GetAccessibleInShell(aNode, presShell, aAccessible);
}
NS_IMETHODIMP
nsAccessibilityService::GetAttachedAccessibleFor(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG(aNode);
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
nsCOMPtr<nsIDOMNode> relevantNode;
nsresult rv = GetRelevantContentNodeFor(aNode, getter_AddRefs(relevantNode));
NS_ENSURE_SUCCESS(rv, rv);
if (relevantNode != aNode)
return NS_OK;
return GetAccessibleFor(aNode, aAccessible);
}
NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWindow(nsIDOMNode *aNode,
nsIDOMWindow *aWin,
nsIAccessible **aAccessible)
@ -1303,6 +1323,73 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
return InitAccessible(newAcc, aAccessible);
}
NS_IMETHODIMP
nsAccessibilityService::GetRelevantContentNodeFor(nsIDOMNode *aNode,
nsIDOMNode **aRelevantNode)
{
// The method returns node that is relevant for attached accessible check.
// Sometimes element that is XBL widget hasn't accessible children in
// anonymous content. This method check whether given node can be accessible
// by looking through all nested bindings that given node is anonymous for. If
// there is XBL widget that deniedes to be accessible for given node then the
// method returns that XBL widget otherwise it returns given node.
// For example, the algorithm allows us to handle following cases:
// 1. xul:dialog element has buttons (like 'ok' and 'cancel') in anonymous
// content. When node is dialog's button then we dialog's button since button
// of xul:dialog is accessible anonymous node.
// 2. xul:texbox has html:input in anonymous content. When given node is
// html:input elmement then we return xul:textbox since xul:textbox doesn't
// allow accessible nodes in anonymous content.
// 3. xforms:input that is hosted in xul document contains xul:textbox
// element. When given node is html:input or xul:textbox then we return
// xforms:input element since xforms:input hasn't accessible anonymous
// children.
NS_ENSURE_ARG(aNode);
NS_ENSURE_ARG_POINTER(aRelevantNode);
nsresult rv;
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
if (content) {
// Build stack of binding parents so we can walk it in reverse.
nsIContent *bindingParent;
nsCOMArray<nsIContent> bindingsStack;
for (bindingParent = content->GetBindingParent(); bindingParent != nsnull;
bindingParent = bindingParent->GetBindingParent()) {
bindingsStack.AppendObject(bindingParent);
}
PRInt32 bindingsCount = bindingsStack.Count();
for (PRInt32 index = bindingsCount - 1; index >= 0 ; index--) {
bindingParent = bindingsStack[index];
nsCOMPtr<nsIDOMNode> bindingNode(do_QueryInterface(bindingParent));
if (bindingNode) {
// Try to get an accessible by type since XBL widget can be accessible
// only if it implements nsIAccessibleProvider interface.
nsCOMPtr<nsIAccessible> accessible;
rv = GetAccessibleByType(bindingNode, getter_AddRefs(accessible));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsPIAccessible> paccessible(do_QueryInterface(accessible));
if (paccessible) {
PRBool allowsAnonChildren = PR_FALSE;
paccessible->GetAllowsAnonChildAccessibles(&allowsAnonChildren);
if (!allowsAnonChildren) {
NS_ADDREF(*aRelevantNode = bindingNode);
return NS_OK;
}
}
}
}
}
}
NS_ADDREF(*aRelevantNode = aNode);
return NS_OK;
}
nsresult nsAccessibilityService::GetAccessibleByType(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
{

Просмотреть файл

@ -791,27 +791,24 @@ void nsRootAccessible::GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNo
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aEvent));
if (nsevent) {
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
nsCOMPtr<nsIContent> content(do_QueryInterface(domEventTarget));
nsIContent *bindingParent;
if (content && content->IsNodeOfType(nsINode::eHTML) &&
(bindingParent = content->GetBindingParent()) != nsnull) {
// Use binding parent when the event occurs in
// anonymous HTML content.
// This gets the following important cases correct:
// 1. Inserted <dialog> buttons like OK, Cancel, Help.
// 2. XUL menulists and comboboxes.
// 3. The focused radio button in a group.
CallQueryInterface(bindingParent, aTargetNode);
NS_ASSERTION(*aTargetNode, "No target node for binding parent of anonymous event target");
if (!nsevent)
return;
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
nsCOMPtr<nsIDOMNode> eventTarget(do_QueryInterface(domEventTarget));
if (!eventTarget)
return;
nsIAccessibilityService* accService = GetAccService();
if (accService) {
nsresult rv = accService->GetRelevantContentNodeFor(eventTarget,
aTargetNode);
if (NS_SUCCEEDED(rv) && *aTargetNode)
return;
}
if (domEventTarget) {
CallQueryInterface(domEventTarget, aTargetNode);
}
}
NS_ADDREF(*aTargetNode = eventTarget);
}
void nsRootAccessible::FireFocusCallback(nsITimer *aTimer, void *aClosure)

Просмотреть файл

@ -105,7 +105,8 @@
var accService =
Components.classes['@mozilla.org/accessibilityService;1']
.getService(Components.interfaces.nsIAccessibilityService);
return accService.getAccessibleFor(object);
return accService.getAttachedAccessibleFor(object);
} catch(e) {
return false;
}

Просмотреть файл

@ -400,8 +400,10 @@ inDOMView::GetCellProperties(PRInt32 row, nsITreeColumn* col, nsISupportsArray *
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleFor(node->node, getter_AddRefs(accessible));
if (accessible)
nsresult rv =
accService->GetAttachedAccessibleFor(node->node,
getter_AddRefs(accessible));
if (NS_SUCCEEDED(rv) && accessible)
properties->AppendElement(kAccessibleNodeAtom);
}
#endif