From 1f4dd4eab95affeb82ccc59e53f09f4492e9c56e Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Mon, 11 May 2009 18:57:28 +0800 Subject: [PATCH] Bug 491657 - getDeepestChildAtPoint must return null when point is not inside of accessible, r=marcoz, davidb, sr=neil --- accessible/src/base/nsAccUtils.cpp | 10 ++ accessible/src/base/nsAccUtils.h | 7 + accessible/src/base/nsAccessible.cpp | 132 +++++++++--------- accessible/src/base/nsAccessible.h | 22 ++- .../src/base/nsBaseWidgetAccessible.cpp | 11 ++ accessible/src/base/nsBaseWidgetAccessible.h | 13 +- accessible/src/base/nsOuterDocAccessible.cpp | 41 +++--- accessible/src/base/nsOuterDocAccessible.h | 8 +- accessible/src/html/nsHTMLAreaAccessible.cpp | 10 ++ accessible/src/html/nsHTMLAreaAccessible.h | 5 +- accessible/src/xul/nsXULTreeAccessible.cpp | 20 ++- accessible/src/xul/nsXULTreeAccessible.h | 6 +- accessible/tests/mochitest/Makefile.in | 1 + accessible/tests/mochitest/common.js | 2 + accessible/tests/mochitest/layout.js | 31 +++- .../tests/mochitest/test_childAtPoint.html | 92 ++++++++++++ 16 files changed, 295 insertions(+), 116 deletions(-) create mode 100644 accessible/tests/mochitest/test_childAtPoint.html diff --git a/accessible/src/base/nsAccUtils.cpp b/accessible/src/base/nsAccUtils.cpp index b6ce0624879..a8d4f3cdfd7 100644 --- a/accessible/src/base/nsAccUtils.cpp +++ b/accessible/src/base/nsAccUtils.cpp @@ -715,6 +715,16 @@ nsAccUtils::GetLiveAttrValue(PRUint32 aRule, nsAString& aValue) } } +already_AddRefed +nsAccUtils::QueryAccessible(nsIAccessible *aAccessible) +{ + nsAccessible* accessible = nsnull; + if (aAccessible) + CallQueryInterface(aAccessible, &accessible); + + return accessible; +} + #ifdef DEBUG_A11Y PRBool diff --git a/accessible/src/base/nsAccUtils.h b/accessible/src/base/nsAccUtils.h index a0cabc4661a..7a60ccf305c 100644 --- a/accessible/src/base/nsAccUtils.h +++ b/accessible/src/base/nsAccUtils.h @@ -52,6 +52,7 @@ #include "nsPoint.h" class nsAccessNode; +class nsAccessible; class nsAccUtils { @@ -320,6 +321,12 @@ public: return accessNode; } + /** + * Query nsAccessible from the given nsIAccessible. + */ + static already_AddRefed + QueryAccessible(nsIAccessible *aAccessible); + #ifdef DEBUG_A11Y /** * Detect whether the given accessible object implements nsIAccessibleText, diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index b124efc466c..0635ffce67e 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -1082,29 +1082,23 @@ NS_IMETHODIMP nsAccessible::GetFocusedChild(nsIAccessible **aFocusedChild) return NS_OK; } -// nsIAccessible getDeepestChildAtPoint(in long x, in long y) -NS_IMETHODIMP -nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, - nsIAccessible **aAccessible) +// nsAccessible::GetChildAtPoint() +nsresult +nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, PRBool aDeepestChild, + nsIAccessible **aChild) { - 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 + // we return |this| if the point is within it, otherwise nsnull. + PRInt32 x = 0, y = 0, width = 0, height = 0; + nsresult rv = GetBounds(&x, &y, &width, &height); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr fallbackAnswer; - PRInt32 x, y, width, height; - GetBounds(&x, &y, &width, &height); - if (aX >= x && aX < x + width && - aY >= y && aY < y + height) { + if (aX >= x && aX < x + width && aY >= y && aY < y + height) fallbackAnswer = this; - } + if (nsAccUtils::MustPrune(this)) { // Do not dig any further - NS_IF_ADDREF(*aAccessible = fallbackAnswer); + NS_IF_ADDREF(*aChild = fallbackAnswer); return NS_OK; } @@ -1115,7 +1109,7 @@ nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, // for DOM parent but GetFrameForPoint() should be called for containing block // to get an out of flow element. nsCOMPtr accDocument; - nsresult rv = GetAccessibleDocument(getter_AddRefs(accDocument)); + rv = GetAccessibleDocument(getter_AddRefs(accDocument)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(accDocument, NS_ERROR_FAILURE); @@ -1133,9 +1127,10 @@ nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, nsCOMPtr presShell = presContext->PresShell(); nsIFrame *foundFrame = presShell->GetFrameForPoint(frame, offset); - nsCOMPtr content; + + nsIContent* content = nsnull; if (!foundFrame || !(content = foundFrame->GetContent())) { - NS_IF_ADDREF(*aAccessible = fallbackAnswer); + NS_IF_ADDREF(*aChild = fallbackAnswer); return NS_OK; } @@ -1145,7 +1140,7 @@ nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, nsCOMPtr relevantNode; accService->GetRelevantContentNodeFor(node, getter_AddRefs(relevantNode)); if (!relevantNode) { - NS_IF_ADDREF(*aAccessible = fallbackAnswer); + NS_IF_ADDREF(*aChild = fallbackAnswer); return NS_OK; } @@ -1157,16 +1152,17 @@ nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, accDocument->GetAccessibleInParentChain(relevantNode, PR_TRUE, getter_AddRefs(accessible)); if (!accessible) { - NS_IF_ADDREF(*aAccessible = fallbackAnswer); + NS_IF_ADDREF(*aChild = fallbackAnswer); return NS_OK; } } 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 + // Manually walk through accessible children and see if the are within this + // point. Skip offscreen or invisible accessibles. This takes care of cases + // where layout won't walk into things for us, such as image map areas and + // sub documents (XXX: subdocuments should be handled by methods of + // nsOuterDocAccessibles). nsCOMPtr child; while (NextChild(child)) { PRInt32 childX, childY, childWidth, childHeight; @@ -1174,16 +1170,40 @@ nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, if (aX >= childX && aX < childX + childWidth && aY >= childY && aY < childY + childHeight && (nsAccUtils::State(child) & nsIAccessibleStates::STATE_INVISIBLE) == 0) { - // Don't walk into offscreen or invisible items - NS_IF_ADDREF(*aAccessible = child); + + if (aDeepestChild) + return child->GetDeepestChildAtPoint(aX, aY, aChild); + + NS_IF_ADDREF(*aChild = 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 + + // The point is in this accessible but not in a child. We are allowed to + // return |this| as the answer. + NS_IF_ADDREF(*aChild = accessible); + return NS_OK; + } + + // Since DOM node of obtained accessible may be out of flow then we should + // ensure obtained accessible is a child of this accessible. + nsCOMPtr parent, child(accessible); + while (PR_TRUE) { + child->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(*aChild = fallbackAnswer); + return NS_OK; + } + + if (parent == this) { + NS_ADDREF(*aChild = (aDeepestChild ? accessible : child)); + return NS_OK; + } + child.swap(parent); } - NS_IF_ADDREF(*aAccessible = accessible); return NS_OK; } @@ -1192,43 +1212,27 @@ NS_IMETHODIMP nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aAccessible) { - nsresult rv = GetDeepestChildAtPoint(aX, aY, aAccessible); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_ARG_POINTER(aAccessible); + *aAccessible = nsnull; - if (!*aAccessible || *aAccessible == this) - return NS_OK; + if (IsDefunct()) + return NS_ERROR_FAILURE; - // Get direct child containing the deepest child at the given point. - nsCOMPtr parent, accessible; - accessible.swap(*aAccessible); + return GetChildAtPoint(aX, aY, PR_FALSE, aAccessible); +} - while (PR_TRUE) { - accessible->GetParent(getter_AddRefs(parent)); - if (!parent) { - NS_NOTREACHED("Obtained accessible isn't a child of this accessible."); +// nsIAccessible getDeepestChildAtPoint(in long x, in long y) +NS_IMETHODIMP +nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, + nsIAccessible **aAccessible) +{ + NS_ENSURE_ARG_POINTER(aAccessible); + *aAccessible = nsnull; - // Reached the top of the hierarchy. These bounds were inside an - // accessible that is not a descendant of this one. + if (IsDefunct()) + return NS_ERROR_FAILURE; - // 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; + return GetChildAtPoint(aX, aY, PR_TRUE, aAccessible); } void nsAccessible::GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame) diff --git a/accessible/src/base/nsAccessible.h b/accessible/src/base/nsAccessible.h index a58f3b432e1..a180a7c724c 100644 --- a/accessible/src/base/nsAccessible.h +++ b/accessible/src/base/nsAccessible.h @@ -104,11 +104,11 @@ private: #define NS_ACCESSIBLE_IMPL_CID \ -{ /* 4E36C7A8-9203-4ef9-B619-271DDF6BB839 */ \ - 0x4e36c7a8, \ - 0x9203, \ - 0x4ef9, \ - { 0xb6, 0x19, 0x27, 0x1d, 0xdf, 0x6b, 0xb8, 0x39 } \ +{ /* 16917f1e-6cee-4cde-be3f-8bb5943f506c */ \ + 0x16917f1e, \ + 0x6cee, \ + 0x4cde, \ + { 0xbe, 0x3f, 0x8b, 0xb5, 0x94, 0x3F, 0x50, 0x6c } \ } class nsAccessible : public nsAccessNodeWrap, @@ -179,6 +179,18 @@ public: */ virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes); + /** + * Return direct or deepest child at the given point. + * + * @param aX [in] x coordinate relative screen + * @param aY [in] y coordinate relative screen + * @param aDeepestChild [in] flag points if deep child should be returned + * @param aChild [out] found child + */ + virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild); + ////////////////////////////////////////////////////////////////////////////// // Helper methods diff --git a/accessible/src/base/nsBaseWidgetAccessible.cpp b/accessible/src/base/nsBaseWidgetAccessible.cpp index 8606cd442c3..90c01d4179d 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.cpp +++ b/accessible/src/base/nsBaseWidgetAccessible.cpp @@ -94,6 +94,17 @@ nsLeafAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren) return NS_OK; } +// nsAccessible::GetChildAtPoint() +nsresult +nsLeafAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild) +{ + // Don't walk into leaf accessibles. + NS_ADDREF(*aChild = this); + return NS_OK; +} + //////////////////////////////////////////////////////////////////////////////// // nsLinkableAccessible diff --git a/accessible/src/base/nsBaseWidgetAccessible.h b/accessible/src/base/nsBaseWidgetAccessible.h index 12683999bd1..bed7c956071 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.h +++ b/accessible/src/base/nsBaseWidgetAccessible.h @@ -58,13 +58,22 @@ class nsLeafAccessible : public nsAccessibleWrap { public: nsLeafAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell); + + // nsISupports NS_DECL_ISUPPORTS_INHERITED + + // nsIAccessible NS_IMETHOD GetFirstChild(nsIAccessible **_retval); NS_IMETHOD GetLastChild(nsIAccessible **_retval); NS_IMETHOD GetChildCount(PRInt32 *_retval); + + // nsPIAccessible NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren); - NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aAccessible) - { NS_ENSURE_ARG_POINTER(aAccessible); NS_ADDREF(*aAccessible = this); return NS_OK; } // Don't walk into these + + // nsAccessible + virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild); }; /** diff --git a/accessible/src/base/nsOuterDocAccessible.cpp b/accessible/src/base/nsOuterDocAccessible.cpp index 2accc40eb40..1676fc8c2d4 100644 --- a/accessible/src/base/nsOuterDocAccessible.cpp +++ b/accessible/src/base/nsOuterDocAccessible.cpp @@ -70,40 +70,33 @@ nsOuterDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState) return NS_OK; } -// nsIAccessible::getChildAtPoint(in long x, in long y) -NS_IMETHODIMP +// nsAccessible::GetChildAtPoint() +nsresult nsOuterDocAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, - nsIAccessible **aAccessible) + PRBool aDeepestChild, + nsIAccessible **aChild) { - 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; - } + PRInt32 docX = 0, docY = 0, docWidth = 0, docHeight = 0; + nsresult rv = GetBounds(&docX, &docY, &docWidth, &docHeight); + NS_ENSURE_SUCCESS(rv, rv); - return GetFirstChild(aAccessible); // Always return the inner doc unless bounds outside of it -} + if (aX < docX || aX >= docX + docWidth || aY < docY || aY >= docY + docHeight) + return NS_OK; -// 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. + // Always return the inner doc as direct child accessible unless bounds + // outside of it. nsCOMPtr childAcc; - nsresult rv = GetChildAtPoint(aX, aY, getter_AddRefs(childAcc)); + rv = GetFirstChild(getter_AddRefs(childAcc)); NS_ENSURE_SUCCESS(rv, rv); if (!childAcc) return NS_OK; - return childAcc->GetDeepestChildAtPoint(aX, aY, aAccessible); + if (aDeepestChild) + return childAcc->GetDeepestChildAtPoint(aX, aY, aChild); + + NS_ADDREF(*aChild = childAcc); + return NS_OK; } void nsOuterDocAccessible::CacheChildren() diff --git a/accessible/src/base/nsOuterDocAccessible.h b/accessible/src/base/nsOuterDocAccessible.h index f8fa63cdd1c..bb0a3accd56 100644 --- a/accessible/src/base/nsOuterDocAccessible.h +++ b/accessible/src/base/nsOuterDocAccessible.h @@ -55,11 +55,6 @@ public: nsIWeakReference* aShell); // nsIAccessible - NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY, - nsIAccessible **aAccessible); - NS_IMETHOD GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, - nsIAccessible **aAccessible); - NS_IMETHOD GetNumActions(PRUint8 *aNumActions); NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName); NS_IMETHOD GetActionDescription(PRUint8 aIndex, nsAString& aDescription); @@ -69,6 +64,9 @@ public: virtual nsresult GetRoleInternal(PRUint32 *aRole); virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState); virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes); + virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild); protected: // nsAccessible diff --git a/accessible/src/html/nsHTMLAreaAccessible.cpp b/accessible/src/html/nsHTMLAreaAccessible.cpp index 51dad182d7c..f9f336c704f 100644 --- a/accessible/src/html/nsHTMLAreaAccessible.cpp +++ b/accessible/src/html/nsHTMLAreaAccessible.cpp @@ -161,3 +161,13 @@ nsHTMLAreaAccessible::GetBounds(PRInt32 *x, PRInt32 *y, return NS_OK; } +// nsAccessible::GetChildAtPoint() +nsresult +nsHTMLAreaAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild) +{ + // Don't walk into area accessibles. + NS_ADDREF(*aChild = this); + return NS_OK; +} diff --git a/accessible/src/html/nsHTMLAreaAccessible.h b/accessible/src/html/nsHTMLAreaAccessible.h index 057a94b71ab..49f25b6b4d4 100644 --- a/accessible/src/html/nsHTMLAreaAccessible.h +++ b/accessible/src/html/nsHTMLAreaAccessible.h @@ -59,11 +59,12 @@ public: NS_IMETHOD GetChildCount(PRInt32 *_retval); NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height); - NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aAccessible) - { NS_ENSURE_ARG_POINTER(aAccessible); NS_ADDREF(*aAccessible = this); return NS_OK; } // Don't walk into these // nsAccessible virtual nsresult GetNameInternal(nsAString& aName); + virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild); }; #endif diff --git a/accessible/src/xul/nsXULTreeAccessible.cpp b/accessible/src/xul/nsXULTreeAccessible.cpp index 7021d5d57c8..a2ad1e711f8 100644 --- a/accessible/src/xul/nsXULTreeAccessible.cpp +++ b/accessible/src/xul/nsXULTreeAccessible.cpp @@ -318,10 +318,11 @@ NS_IMETHODIMP nsXULTreeAccessible::GetFocusedChild(nsIAccessible **aFocusedChild return NS_OK; } -// nsIAccessible::getDeepestChildAtPoint(in long x, in long y) -NS_IMETHODIMP -nsXULTreeAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, - nsIAccessible **aAccessible) +// nsAccessible::GetChildAtPoint() +nsresult +nsXULTreeAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild) { nsIFrame *frame = GetFrame(); if (!frame) @@ -350,9 +351,16 @@ nsXULTreeAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, // tree columns. if (row == -1 || !column) return nsXULSelectableAccessible:: - GetDeepestChildAtPoint(aX, aY, aAccessible); + GetChildAtPoint(aX, aY, aDeepestChild, aChild); - return GetCachedTreeitemAccessible(row, column, aAccessible); + nsCOMPtr treeitemAcc; + nsresult rv = GetCachedTreeitemAccessible(row, column, + getter_AddRefs(treeitemAcc)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_IF_ADDREF(*aChild = treeitemAcc); + + return NS_OK; } // Ask treeselection to get all selected children diff --git a/accessible/src/xul/nsXULTreeAccessible.h b/accessible/src/xul/nsXULTreeAccessible.h index d8b7f4edb00..f9ea24f2f51 100644 --- a/accessible/src/xul/nsXULTreeAccessible.h +++ b/accessible/src/xul/nsXULTreeAccessible.h @@ -69,15 +69,15 @@ public: NS_IMETHOD GetChildCount(PRInt32 *_retval); NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild); - NS_IMETHOD GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, - nsIAccessible **aAccessible); - // nsAccessNode virtual nsresult Shutdown(); // nsAccessible virtual nsresult GetRoleInternal(PRUint32 *aRole); virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState); + virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY, + PRBool aDeepestChild, + nsIAccessible **aChild); // nsXULTreeAccessible static void GetTreeBoxObject(nsIDOMNode* aDOMNode, nsITreeBoxObject** aBoxObject); diff --git a/accessible/tests/mochitest/Makefile.in b/accessible/tests/mochitest/Makefile.in index 1b91e21b212..fa8326f420e 100644 --- a/accessible/tests/mochitest/Makefile.in +++ b/accessible/tests/mochitest/Makefile.in @@ -76,6 +76,7 @@ _TEST_FILES =\ test_aria_role_grid.html \ test_aria_token_attrs.html \ test_bug420863.html \ + test_childAtPoint.html \ $(warning test_childAtPoint.xul temporarily disabled) \ test_cssattrs.html \ test_descr.html \ diff --git a/accessible/tests/mochitest/common.js b/accessible/tests/mochitest/common.js index 996402983ad..c242db4d4c5 100644 --- a/accessible/tests/mochitest/common.js +++ b/accessible/tests/mochitest/common.js @@ -40,7 +40,9 @@ const nsIDOMDocument = Components.interfaces.nsIDOMDocument; const nsIDOMEvent = Components.interfaces.nsIDOMEvent; const nsIDOMHTMLDocument = Components.interfaces.nsIDOMHTMLDocument; const nsIDOMNode = Components.interfaces.nsIDOMNode; +const nsIDOMNSHTMLElement = Components.interfaces.nsIDOMNSHTMLElement; const nsIDOMWindow = Components.interfaces.nsIDOMWindow; +const nsIDOMXULElement = Components.interfaces.nsIDOMXULElement; const nsIPropertyElement = Components.interfaces.nsIPropertyElement; diff --git a/accessible/tests/mochitest/layout.js b/accessible/tests/mochitest/layout.js index b620a2b5491..8fde9ad01e7 100644 --- a/accessible/tests/mochitest/layout.js +++ b/accessible/tests/mochitest/layout.js @@ -12,14 +12,13 @@ function testChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild, aChildIdentifier) { var childAcc = getAccessible(aChildIdentifier); - if (!childAcc) - return; - var actualChildAcc = getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild); + var msg = "Wrong " + (aFindDeepestChild ? "deepest" : "direct"); msg += " child accessible [" + prettyName(actualChildAcc); msg += "] at the point (" + aX + ", " + aY + ") of accessible ["; msg += prettyName(aIdentifier) + "]"; + is(childAcc, actualChildAcc, msg); } @@ -42,8 +41,7 @@ function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) if (!acc || !node) return; - var deltaX = node.boxObject.screenX; - var deltaY = node.boxObject.screenY; + var [deltaX, deltaY] = getScreenCoords(node); var x = deltaX + aX; var y = deltaY + aY; @@ -56,3 +54,26 @@ function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) return null; } + +/** + * Return DOM node coordinates relative screen as pair (x, y). + */ +function getScreenCoords(aNode) +{ + if (aNode instanceof nsIDOMXULElement) + return [node.boxObject.screenX, node.boxObject.screenY]; + + // Ugly hack until bug 486200 is fixed. + const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + var descr = document.createElementNS(XUL_NS, "description"); + descr.setAttribute("value", "helper description"); + aNode.parentNode.appendChild(descr); + var descrBoxObject = descr.boxObject; + var descrRect = descr.getBoundingClientRect(); + var deltaX = descrBoxObject.screenX - descrRect.left; + var deltaY = descrBoxObject.screenY - descrRect.top; + aNode.parentNode.removeChild(descr); + + var rect = aNode.getBoundingClientRect(); + return [rect.left + deltaX, rect.top + deltaY]; +} diff --git a/accessible/tests/mochitest/test_childAtPoint.html b/accessible/tests/mochitest/test_childAtPoint.html new file mode 100644 index 00000000000..cade1a3d153 --- /dev/null +++ b/accessible/tests/mochitest/test_childAtPoint.html @@ -0,0 +1,92 @@ + + + + nsIAccessible::childAtPoint() tests + + + + + + + + + + + + + Mozilla Bug 491657 +

+ +
+  
+ +
+
imgitem
+
+ + label1label2 + + btn1btn2 + +
+
+
+ + +