Bug 455442 - improve hitTest, r=aaronlev, hwaara

This commit is contained in:
Alexander Surkov 2008-09-17 21:11:39 +08:00
parent c0b37d2110
commit b8ef5046cc
7 changed files with 100 additions and 32 deletions

View File

@ -58,7 +58,7 @@ interface nsIAccessibleRelation;
*
* @status UNDER_REVIEW
*/
[scriptable, uuid(004b6882-2df1-49df-bb5f-0fb81a5b1edf)]
[scriptable, uuid(c7520419-87ec-42bc-98cc-04c0bf173530)]
interface nsIAccessible : nsISupports
{
/**
@ -199,9 +199,25 @@ interface nsIAccessible : nsISupports
* current accessible will be returned.
* If the point is in neither the current accessible or a child, then
* null will be returned.
*
* @param x screen's x coordinate
* @param y screen's y coordinate
* @return the deepest accessible child containing the given point
*/
nsIAccessible getChildAtPoint(in long x, in long y);
/**
* Deepest 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.
*
* @param x screen's x coordinate
* @param y screen's y coordinate
* @return the deepest accessible child containing the given point
*/
nsIAccessible getDeepestChildAtPoint(in long x, in long y);
/**
* Nth accessible child using zero-based index or last child if index less than zero
*/

View File

@ -1104,10 +1104,10 @@ NS_IMETHODIMP nsAccessible::GetFocusedChild(nsIAccessible **aFocusedChild)
return NS_OK;
}
/* nsIAccessible getChildAtPoint (in long x, in long y); */
// nsIAccessible getDeepestChildAtPoint(in long x, in long y)
NS_IMETHODIMP
nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
@ -1205,29 +1205,52 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
// 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;
}
// nsIAccessible getChildAtPoint(in long x, in long y)
NS_IMETHODIMP
nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
{
nsresult rv = GetDeepestChildAtPoint(aX, aY, aAccessible);
NS_ENSURE_SUCCESS(rv, rv);
if (!*aAccessible)
return NS_OK;
nsCOMPtr<nsIAccessible> parent, accessible(*aAccessible);
while (PR_TRUE) {
accessible->GetParent(getter_AddRefs(parent));
if (!parent) {
NS_ASSERTION(PR_FALSE,
"Obtained accessible isn't a child of this accessible.");
// Reached the top of the hierarchy. These bounds were inside an
// accessible that is not a descendant of this one.
// 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.
PRInt32 x, y, width, height;
GetBounds(&x, &y, &width, &height);
if (aX >= x && aX < x + width && aY >= y && aY < y + height)
NS_ADDREF(*aAccessible = this);
return NS_OK;
}
if (parent == this) {
// We reached |this|, so |accessible| is the child we want to return.
NS_ADDREF(*aAccessible = accessible);
return NS_OK;
}
accessible.swap(parent);
}
return NS_OK;
}
void nsAccessible::GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame)
{
/*

View File

@ -67,6 +67,7 @@ nsOuterDocAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
return NS_OK;
}
// nsIAccessible::getChildAtPoint(in long x, in long y)
NS_IMETHODIMP
nsOuterDocAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
@ -85,6 +86,23 @@ nsOuterDocAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
return GetFirstChild(aAccessible); // Always return the inner doc unless bounds outside of it
}
// nsIAccessible::getDeepestChildAtPoint(in long x, in long y)
NS_IMETHODIMP
nsOuterDocAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
{
// Call getDeepestChildAtPoint on the fist child accessible of the outer
// document accessible if the given point is inside of outer document.
nsCOMPtr<nsIAccessible> childAcc;
nsresult rv = GetChildAtPoint(aX, aY, getter_AddRefs(childAcc));
NS_ENSURE_SUCCESS(rv, rv);
if (!childAcc)
return NS_OK;
return childAcc->GetDeepestChildAtPoint(aX, aY, aAccessible);
}
void nsOuterDocAccessible::CacheChildren()
{
// An outer doc accessible usually has 1 nsDocAccessible child,

View File

@ -54,8 +54,12 @@ class nsOuterDocAccessible : public nsAccessibleWrap
NS_IMETHOD GetRole(PRUint32 *aRole);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible);
NS_IMETHOD GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible);
void CacheChildren();
nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
NS_IMETHOD GetNumActions(PRUint8 *aNumActions);

View File

@ -293,22 +293,17 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
{
if (mIsExpired)
return nil;
// Convert from cocoa's coordinate system to gecko's. According to the docs
// the point we're given is guaranteed to be bottom-left screen coordinates.
nsPoint geckoPoint;
ConvertCocoaToGeckoPoint (point, geckoPoint);
// start iterating as deep down as we can on this point, with the current accessible as the root.
// as soon as GetChildAtPoint() returns null, or can't descend further (without getting the same accessible again)
// we stop.
nsCOMPtr<nsIAccessible> deepestFoundChild, newChild(mGeckoAccessible);
do {
deepestFoundChild = newChild;
deepestFoundChild->GetChildAtPoint((PRInt32)geckoPoint.x, (PRInt32)geckoPoint.y, getter_AddRefs(newChild));
} while (newChild && newChild.get() != deepestFoundChild.get());
nsCOMPtr<nsIAccessible> deepestFoundChild;
mGeckoAccessible->GetDeepestChildAtPoint((PRInt32)geckoPoint.x,
(PRInt32)geckoPoint.y,
getter_AddRefs(deepestFoundChild));
// if we found something, return its native accessible.
if (deepestFoundChild) {
mozAccessible *nativeChild = GetNativeFromGeckoAccessible(deepestFoundChild);

View File

@ -355,6 +355,15 @@ nsXULTreeAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
return GetCachedTreeitemAccessible(row, column, aAccessible);
}
// nsIAccessible::getDeepestChildAtPoint(in long x, in long y)
NS_IMETHODIMP
nsXULTreeAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
{
// Call getChildAtPoint until tree doesn't support complex content.
return GetChildAtPoint(aX, aY, aAccessible);
}
// Ask treeselection to get all selected children
NS_IMETHODIMP nsXULTreeAccessible::GetSelectedChildren(nsIArray **_retval)
{

View File

@ -71,8 +71,11 @@ public:
NS_IMETHOD GetLastChild(nsIAccessible **_retval);
NS_IMETHOD GetChildCount(PRInt32 *_retval);
NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible);
NS_IMETHOD GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible);
static void GetTreeBoxObject(nsIDOMNode* aDOMNode, nsITreeBoxObject** aBoxObject);
static nsresult GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32 *aCount);