Bug 395081. AccessibleObjectFromPoint() returns errors. r=surkov, a=dsicore

This commit is contained in:
aaronleventhal@moonset.net 2007-09-18 14:44:43 -07:00
parent 558c745412
commit 781ab06e6b
6 changed files with 102 additions and 20 deletions

View File

@ -194,6 +194,10 @@ interface nsIAccessible : nsISupports
/**
* Accessible child which contains the coordinate at (x, y) in screen pixels.
* If the point is in the current accessible but not in a child, the
* current accessible will be returned.
* If the point is in neither the current accessible or a child, then
* null will be returned.
*/
nsIAccessible getChildAtPoint(in long x, in long y);

View File

@ -1064,6 +1064,24 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
if (!mDOMNode) {
return NS_ERROR_FAILURE; // Already shut down
}
// If we can't find the point in a child, we will return the fallback answer:
// we return |this| if the point is within it, otherwise nsnull
nsCOMPtr<nsIAccessible> fallbackAnswer;
PRInt32 x, y, width, height;
GetBounds(&x, &y, &width, &height);
if (aX >= x && aX < x + width &&
aY >= y && aY < y + height) {
fallbackAnswer = this;
}
if (MustPrune(this)) { // Do not dig any further
NS_IF_ADDREF(*aAccessible = fallbackAnswer);
return NS_OK;
}
// Search an accessible at the given point starting from accessible document
// because containing block (see CSS2) for out of flow element (for example,
// absolutely positioned element) may be different from its DOM parent and
@ -1073,9 +1091,7 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsCOMPtr<nsIAccessibleDocument> accDocument;
nsresult rv = GetAccessibleDocument(getter_AddRefs(accDocument));
NS_ENSURE_SUCCESS(rv, rv);
if (!accDocument)
return NS_OK;
NS_ENSURE_TRUE(accDocument, NS_ERROR_FAILURE);
nsCOMPtr<nsPIAccessNode> accessNodeDocument(do_QueryInterface(accDocument));
NS_ASSERTION(accessNodeDocument,
@ -1092,37 +1108,75 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
nsIFrame *foundFrame = presShell->GetFrameForPoint(frame, offset);
if (!foundFrame)
return NS_OK;
nsCOMPtr<nsIContent> content(foundFrame->GetContent());
if (!content)
nsCOMPtr<nsIContent> content;
if (!foundFrame || !(content = foundFrame->GetContent())) {
NS_IF_ADDREF(*aAccessible = fallbackAnswer);
return NS_OK;
}
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
nsCOMPtr<nsIDOMNode> relevantNode;
accService->GetRelevantContentNodeFor(node, getter_AddRefs(relevantNode));
if (!relevantNode)
if (!relevantNode) {
NS_IF_ADDREF(*aAccessible = fallbackAnswer);
return NS_OK;
}
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleFor(relevantNode, getter_AddRefs(accessible));
if (!accessible)
if (!accessible) {
// No accessible for the node with the point, so find the first
// accessible in the DOM parent chain
accDocument->GetAccessibleInParentChain(relevantNode,
getter_AddRefs(accessible));
if (!accessible) {
NS_IF_ADDREF(*aAccessible = fallbackAnswer);
return NS_OK;
nsCOMPtr<nsIAccessible> parent;
accessible->GetParent(getter_AddRefs(parent));
while (parent && parent != this) {
accessible.swap(parent);
accessible->GetParent(getter_AddRefs(parent));
}
}
if (parent)
NS_ADDREF(*aAccessible = accessible);
if (accessible == this) {
// Manually walk through accessible children and see if
// the are within this point.
// This takes care of cases where layout won't walk into
// things for us, such as image map areas and sub documents
nsCOMPtr<nsIAccessible> child;
while (NextChild(child)) {
PRInt32 childX, childY, childWidth, childHeight;
child->GetBounds(&childX, &childY, &childWidth, &childHeight);
if (aX >= childX && aX < childX + childWidth &&
aY >= childY && aY < childY + childHeight &&
(State(child) & nsIAccessibleStates::STATE_INVISIBLE) == 0) {
// Don't walk into offscreen or invisible items
NS_IF_ADDREF(*aAccessible = child);
return NS_OK;
}
}
// Fall through -- the point is in this accessible but not in a child
// We are allowed to return |this| as the answer
}
else {
nsCOMPtr<nsIAccessible> parent;
while (PR_TRUE) {
accessible->GetParent(getter_AddRefs(parent));
if (!parent) {
// Reached the top of the hierarchy
// these bounds were inside an accessible that is not a descendant of this one
NS_IF_ADDREF(*aAccessible = fallbackAnswer);
return NS_OK;
}
if (parent == this) {
// We reached |this|, so |accessible| is the
// child we want to return
break;
}
accessible.swap(parent);
}
}
NS_IF_ADDREF(*aAccessible = accessible);
return NS_OK;
}

View File

@ -63,6 +63,8 @@ public:
NS_IMETHOD GetLastChild(nsIAccessible **_retval);
NS_IMETHOD GetChildCount(PRInt32 *_retval);
NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren);
NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aAccessible)
{ *aAccessible = this; return NS_OK; } // Don't walk into these
};
/**

View File

@ -86,6 +86,24 @@ nsOuterDocAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
return NS_OK;
}
NS_IMETHODIMP
nsOuterDocAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
if (!mDOMNode) {
return NS_ERROR_FAILURE;
}
PRInt32 docX, docY, docWidth, docHeight;
GetBounds(&docX, &docY, &docWidth, &docHeight);
if (aX < docX || aX >= docX + docWidth || aY < docY || aY >= docY + docHeight) {
return NS_ERROR_FAILURE;
}
return GetFirstChild(aAccessible); // Always return the inner doc unless bounds outside of it
}
void nsOuterDocAccessible::CacheChildren()
{
// An outer doc accessible usually has 1 nsDocAccessible child,

View File

@ -55,6 +55,8 @@ class nsOuterDocAccessible : public nsAccessibleWrap
NS_IMETHOD GetName(nsAString& aName);
NS_IMETHOD GetRole(PRUint32 *aRole);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible);
void CacheChildren();
};

View File

@ -56,6 +56,8 @@ public:
NS_IMETHOD GetChildCount(PRInt32 *_retval);
NS_IMETHOD GetDescription(nsAString& _retval);
NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aAccessible)
{ *aAccessible = this; return NS_OK; } // Don't walk into these
};
#endif