Bug 388927 - getChildAtPoint fails for scrolled content, r=evan.yan, roc, sr=roc, a=dsicore

This commit is contained in:
surkov.alexander@gmail.com 2007-09-05 01:00:40 -07:00
Родитель c881ad990f
Коммит 00631daa97
5 изменённых файлов: 115 добавлений и 58 удалений

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

@ -1082,70 +1082,73 @@ NS_IMETHODIMP nsAccessible::GetFocusedChild(nsIAccessible **aFocusedChild)
}
/* nsIAccessible getChildAtPoint (in long x, in long y); */
NS_IMETHODIMP nsAccessible::GetChildAtPoint(PRInt32 tx, PRInt32 ty, nsIAccessible **aAccessible)
NS_IMETHODIMP
nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
nsCOMPtr<nsIAccessible> child;
GetFirstChild(getter_AddRefs(child));
// 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
// therefore accessible for containing block may be different from accessible
// for DOM parent but GetFrameForPoint() should be called for containing block
// to get an out of flow element.
nsCOMPtr<nsIAccessibleDocument> accDocument;
nsresult rv = GetAccessibleDocument(getter_AddRefs(accDocument));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 x, y, w, h;
PRUint32 state;
nsCOMPtr<nsIAccessible> childAtPoint;
while (child) {
child->GetBounds(&x, &y, &w, &h);
if (tx >= x && tx < x + w && ty >= y && ty < y + h) {
nsCOMPtr<nsPIAccessNode> accessNode(do_QueryInterface(child));
if (accessNode) {
nsIFrame *frame = accessNode->GetFrame();
if (!frame) {
state = State(child);
// In some cases accessibles don't have a frame; examples are
// tree items or combo box dropdown markers. For these cases
// just ensure that the returned accessible is visible.
if ((state & (nsIAccessibleStates::STATE_OFFSCREEN |
nsIAccessibleStates::STATE_INVISIBLE)) == 0) {
// Don't walk into offscreen or invisible items
NS_IF_ADDREF(*aAccessible = child);
return NS_OK;
}
}
else {
// If there are multiple accessibles the contain the point
// and they overlap then pick the one with a frame that contains the point
// For example, A point that's in block #2 is also in block #1, but we want to return #2:
// [[block #1 is long wrapped text that continues to
// another line]] [[here is a shorter block #2]]
while (frame) {
if (frame->GetScreenRectExternal().Contains(tx, ty)) {
childAtPoint = child;
break; // Definitely in this accessible, since one of its frame matches the point
}
frame = frame->GetNextContinuation();
}
}
}
}
nsCOMPtr<nsIAccessible> next;
child->GetNextSibling(getter_AddRefs(next));
child = next;
}
if (childAtPoint) {
NS_ADDREF(*aAccessible = childAtPoint);
if (!accDocument)
return NS_OK;
}
GetState(&state, nsnull);
GetBounds(&x, &y, &w, &h);
if ((state & (nsIAccessibleStates::STATE_OFFSCREEN |
nsIAccessibleStates::STATE_INVISIBLE)) == 0 &&
tx >= x && tx < x + w && ty >= y && ty < y + h) {
*aAccessible = this;
NS_ADDREF_THIS();
nsCOMPtr<nsPIAccessNode> accessNodeDocument(do_QueryInterface(accDocument));
NS_ASSERTION(accessNodeDocument,
"nsIAccessibleDocument doesn't implement nsPIAccessNode");
nsIFrame *frame = accessNodeDocument->GetFrame();
NS_ENSURE_STATE(frame);
nsPresContext *presContext = frame->PresContext();
nsIntRect screenRect = frame->GetScreenRectExternal();
nsPoint offset(presContext->DevPixelsToAppUnits(aX - screenRect.x),
presContext->DevPixelsToAppUnits(aY - screenRect.y));
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
nsIFrame *foundFrame = presShell->GetFrameForPoint(frame, offset);
if (!foundFrame)
return NS_OK;
nsCOMPtr<nsIContent> content(foundFrame->GetContent());
if (!content)
return NS_OK;
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
nsCOMPtr<nsIDOMNode> relevantNode;
accService->GetRelevantContentNodeFor(node, getter_AddRefs(relevantNode));
if (!relevantNode)
return NS_OK;
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleFor(relevantNode, getter_AddRefs(accessible));
if (!accessible)
return NS_OK;
nsCOMPtr<nsIAccessible> parent;
accessible->GetParent(getter_AddRefs(parent));
while (parent && parent != this) {
accessible.swap(parent);
accessible->GetParent(getter_AddRefs(parent));
}
return NS_ERROR_FAILURE;
if (parent)
NS_ADDREF(*aAccessible = accessible);
return NS_OK;
}
void nsAccessible::GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame)

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

@ -319,6 +319,42 @@ NS_IMETHODIMP nsXULTreeAccessible::GetFocusedChild(nsIAccessible **aFocusedChild
return NS_OK;
}
// nsIAccessible::getChildAtPoint(in long x, in long y)
NS_IMETHODIMP
nsXULTreeAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aAccessible)
{
nsIFrame *frame = GetFrame();
if (!frame)
return NS_ERROR_FAILURE;
nsPresContext *presContext = frame->PresContext();
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
nsIFrame *rootFrame = presShell->GetRootFrame();
NS_ENSURE_STATE(rootFrame);
nsIntRect rootRect = rootFrame->GetScreenRectExternal();
PRInt32 clientX = presContext->AppUnitsToIntCSSPixels(
presContext->DevPixelsToAppUnits(aX - rootRect.x));
PRInt32 clientY = presContext->AppUnitsToIntCSSPixels(
presContext->DevPixelsToAppUnits(aY - rootRect.y));
PRInt32 row = -1;
nsCOMPtr<nsITreeColumn> column;
nsCAutoString childEltUnused;
mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
childEltUnused);
// If we failed to find tree cell for the given point then it might be
// tree columns.
if (row == -1 || !column)
return nsXULSelectableAccessible::GetChildAtPoint(aX, aY, aAccessible);
return GetCachedTreeitemAccessible(row, column, aAccessible);
}
// Ask treeselection to get all selected children
NS_IMETHODIMP nsXULTreeAccessible::GetSelectedChildren(nsIArray **_retval)
{

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

@ -72,6 +72,8 @@ 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);
static void GetTreeBoxObject(nsIDOMNode* aDOMNode, nsITreeBoxObject** aBoxObject);
static nsresult GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32 *aCount);

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

@ -607,6 +607,14 @@ public:
*/
virtual nsresult ReconstructFrames() = 0;
/**
* Given aFrame, the root frame of a stacking context, find its descendant
* frame under the point aPt that receives a mouse event at that location,
* or nsnull if there is no such frame.
* @param aPt the point, relative to the frame origin
*/
virtual nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt) = 0;
/**
* See if reflow verification is enabled. To enable reflow verification add
* "verifyreflow:1" to your NSPR_LOG_MODULES environment variable

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

@ -873,7 +873,9 @@ public:
virtual nsresult ReconstructFrames(void);
virtual void Freeze();
virtual void Thaw();
virtual nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt);
NS_IMETHOD RenderDocument(const nsRect& aRect, PRBool aUntrusted,
PRBool aIgnoreViewportScrolling,
nscolor aBackgroundColor,
@ -2970,6 +2972,12 @@ PresShell::GetPageSequenceFrame(nsIPageSequenceFrame** aResult) const
return *aResult ? NS_OK : NS_ERROR_FAILURE;
}
nsIFrame*
PresShell::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt)
{
return nsLayoutUtils::GetFrameForPoint(aFrame, aPt);
}
void
PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
{