From adbfa3bec2bddfc2bb2cc7375c6b27ab5ffa5b46 Mon Sep 17 00:00:00 2001 From: "surkov.alexander@gmail.com" Date: Mon, 24 Sep 2007 22:48:51 -0700 Subject: [PATCH] Bug 391617 - CAccessibleText::scroll* methods are incorrect, r=aaronlev, a=dsicore --- accessible/public/nsIAccessibleText.idl | 34 +- accessible/public/nsIAccessibleTypes.idl | 3 +- accessible/src/base/nsAccessNode.cpp | 70 +--- accessible/src/base/nsAccessibilityUtils.cpp | 106 +++++- accessible/src/base/nsAccessibilityUtils.h | 44 +++ accessible/src/html/Makefile.in | 1 + accessible/src/html/nsHyperTextAccessible.cpp | 316 ++++++++++++------ accessible/src/html/nsHyperTextAccessible.h | 22 ++ accessible/src/msaa/CAccessibleText.cpp | 30 +- accessible/src/msaa/nsAccessibleWrap.cpp | 11 +- 10 files changed, 422 insertions(+), 215 deletions(-) diff --git a/accessible/public/nsIAccessibleText.idl b/accessible/public/nsIAccessibleText.idl index 89024a12259..af113712c05 100644 --- a/accessible/public/nsIAccessibleText.idl +++ b/accessible/public/nsIAccessibleText.idl @@ -45,7 +45,7 @@ typedef long nsAccessibleTextBoundary; interface nsIAccessible; -[scriptable, uuid(948419b2-53f6-4a74-bb69-1345faf3e8e8)] +[scriptable, uuid(caa4f543-070e-4705-8428-2e53575c41bb)] interface nsIAccessibleText : nsISupports { const nsAccessibleTextBoundary BOUNDARY_CHAR = 0; @@ -180,15 +180,31 @@ interface nsIAccessibleText : nsISupports /** * Makes a specific part of string visible on screen. * - * @param aStartIndex - 0-based character offset. - * @param aEndIndex - 0-based character offset - the offset of the - * character just past the last character of the - * string. - * @param aScrollType - defines how to scroll (see nsIAccessibleScrollType for - * available constants). + * @param startIndex 0-based character offset + * @param endIndex 0-based character offset - the offset of the + * character just past the last character of the + * string + * @param scrollType defines how to scroll (see nsIAccessibleScrollType for + * available constants) */ - void scrollSubstringTo(in long aStartIndex, in long aEndIndex, - in unsigned long aScrollType); + void scrollSubstringTo(in long startIndex, in long endIndex, + in unsigned long scrollType); + + /** + * Moves the top left of a substring to a specified location. + * + * @param startIndex 0-based character offset + * @param endIndex 0-based character offset - the offset of the + * character just past the last character of + * the string + * @param coordinateType specifies the coordinates origin (for available + * constants refer to nsIAccessibleCoordinateType) + * @param x defines the x coordinate + * @param y defines the y coordinate + */ + void scrollSubstringToPoint(in long startIndex, in long endIndex, + in unsigned long coordinateType, + in long x, in long y); }; /* diff --git a/accessible/public/nsIAccessibleTypes.idl b/accessible/public/nsIAccessibleTypes.idl index 0ea7825da29..8bec47113c9 100755 --- a/accessible/public/nsIAccessibleTypes.idl +++ b/accessible/public/nsIAccessibleTypes.idl @@ -90,8 +90,7 @@ interface nsIAccessibleScrollType : nsISupports /** - * These constants define which coordinate system a point is located in. Note, - * keep them synchronized with IA2CoordinateType. + * These constants define which coordinate system a point is located in. */ [scriptable, uuid(c9fbdf10-619e-436f-bf4b-8566686f1577)] interface nsIAccessibleCoordinateType : nsISupports diff --git a/accessible/src/base/nsAccessNode.cpp b/accessible/src/base/nsAccessNode.cpp index 8ddea6d2ce6..38cf7de6558 100755 --- a/accessible/src/base/nsAccessNode.cpp +++ b/accessible/src/base/nsAccessNode.cpp @@ -61,7 +61,6 @@ #include "nsPIDOMWindow.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIFrame.h" -#include "nsIScrollableFrame.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsPresContext.h" @@ -441,71 +440,14 @@ nsAccessNode::ScrollToPoint(PRUint32 aCoordinateType, PRInt32 aX, PRInt32 aY) if (!frame) return NS_ERROR_FAILURE; - nsPresContext *presContext = frame->PresContext(); - - switch (aCoordinateType) { - case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE: - break; - - case nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE: - { - nsIntPoint wndCoords = nsAccUtils::GetScreenCoordsForWindow(mDOMNode); - aX += wndCoords.x; - aY += wndCoords.y; - break; - } - - case nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE: - { - nsCOMPtr parent; - - nsCOMPtr accessible; - nsresult rv = QueryInterface(NS_GET_IID(nsIAccessible), - getter_AddRefs(accessible)); - if (NS_SUCCEEDED(rv) && accessible) { - nsCOMPtr parentAccessible; - accessible->GetParent(getter_AddRefs(parentAccessible)); - parent = do_QueryInterface(parentAccessible); - } else { - nsCOMPtr parentAccessNode; - GetParentNode(getter_AddRefs(parentAccessNode)); - parent = do_QueryInterface(parentAccessNode); - } - - NS_ENSURE_STATE(parent); - nsIFrame *parentFrame = parent->GetFrame(); - NS_ENSURE_STATE(parentFrame); - - nsIntRect parentRect = parentFrame->GetScreenRectExternal(); - aX += parentRect.x; - aY += parentRect.y; - break; - } - - default: - return NS_ERROR_INVALID_ARG; - } + nsIntPoint coords; + nsresult rv = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType, + this, &coords); + NS_ENSURE_SUCCESS(rv, rv); nsIFrame *parentFrame = frame; - while (parentFrame = parentFrame->GetParent()) { - nsIScrollableFrame *scrollableFrame = nsnull; - CallQueryInterface(parentFrame, &scrollableFrame); - if (scrollableFrame) { - nsIntRect frameRect = frame->GetScreenRectExternal(); - PRInt32 devDeltaX = aX - frameRect.x; - PRInt32 devDeltaY = aY - frameRect.y; - - nsPoint deltaPoint; - deltaPoint.x = presContext->DevPixelsToAppUnits(devDeltaX); - deltaPoint.y = presContext->DevPixelsToAppUnits(devDeltaY); - - nsPoint scrollPoint = scrollableFrame->GetScrollPosition(); - - scrollPoint -= deltaPoint; - - scrollableFrame->ScrollTo(scrollPoint); - } - } + while (parentFrame = parentFrame->GetParent()) + nsAccUtils::ScrollFrameToPoint(parentFrame, frame, coords); return NS_OK; } diff --git a/accessible/src/base/nsAccessibilityUtils.cpp b/accessible/src/base/nsAccessibilityUtils.cpp index 1ea88750254..fd4806a58b7 100755 --- a/accessible/src/base/nsAccessibilityUtils.cpp +++ b/accessible/src/base/nsAccessibilityUtils.cpp @@ -40,6 +40,7 @@ #include "nsIAccessibleTypes.h" #include "nsPIAccessible.h" +#include "nsPIAccessNode.h" #include "nsAccessibleEventData.h" #include "nsAccessNode.h" @@ -57,6 +58,7 @@ #include "nsIEventListenerManager.h" #include "nsIPresShell.h" #include "nsPresContext.h" +#include "nsIScrollableFrame.h" #include "nsIEventStateManager.h" #include "nsISelection2.h" #include "nsISelectionController.h" @@ -286,6 +288,19 @@ nsAccUtils::ScrollSubstringTo(nsIFrame *aFrame, nsIDOMNode *aStartNode, PRInt32 aStartIndex, nsIDOMNode *aEndNode, PRInt32 aEndIndex, PRUint32 aScrollType) +{ + PRInt16 vPercent, hPercent; + ConvertScrollTypeToPercents(aScrollType, &vPercent, &hPercent); + + return ScrollSubstringTo(aFrame, aStartNode, aStartIndex, aEndNode, aEndIndex, + vPercent, hPercent); +} + +nsresult +nsAccUtils::ScrollSubstringTo(nsIFrame *aFrame, + nsIDOMNode *aStartNode, PRInt32 aStartIndex, + nsIDOMNode *aEndNode, PRInt32 aEndIndex, + PRInt16 aVPercent, PRInt16 aHPercent) { if (!aFrame || !aStartNode || !aEndNode) return NS_ERROR_FAILURE; @@ -311,10 +326,8 @@ nsAccUtils::ScrollSubstringTo(nsIFrame *aFrame, selection->RemoveAllRanges(); selection->AddRange(scrollToRange); - PRInt16 vPercent, hPercent; - ConvertScrollTypeToPercents(aScrollType, &vPercent, &hPercent); selection->ScrollIntoView(nsISelectionController::SELECTION_ANCHOR_REGION, - PR_TRUE, vPercent, hPercent); + PR_TRUE, aVPercent, aHPercent); selection->CollapseToStart(); } @@ -322,6 +335,32 @@ nsAccUtils::ScrollSubstringTo(nsIFrame *aFrame, return NS_OK; } +void +nsAccUtils::ScrollFrameToPoint(nsIFrame *aScrollableFrame, + nsIFrame *aFrame, + const nsIntPoint& aPoint) +{ + nsIScrollableFrame *scrollableFrame = nsnull; + CallQueryInterface(aScrollableFrame, &scrollableFrame); + if (!scrollableFrame) + return; + + nsPresContext *presContext = aFrame->PresContext(); + + nsIntRect frameRect = aFrame->GetScreenRectExternal(); + PRInt32 devDeltaX = aPoint.x - frameRect.x; + PRInt32 devDeltaY = aPoint.y - frameRect.y; + + nsPoint deltaPoint; + deltaPoint.x = presContext->DevPixelsToAppUnits(devDeltaX); + deltaPoint.y = presContext->DevPixelsToAppUnits(devDeltaY); + + nsPoint scrollPoint = scrollableFrame->GetScrollPosition(); + scrollPoint -= deltaPoint; + + scrollableFrame->ScrollTo(scrollPoint); +} + void nsAccUtils::ConvertScrollTypeToPercents(PRUint32 aScrollType, PRInt16 *aVPercent, @@ -359,6 +398,67 @@ nsAccUtils::ConvertScrollTypeToPercents(PRUint32 aScrollType, } } +nsresult +nsAccUtils::ConvertToScreenCoords(PRInt32 aX, PRInt32 aY, + PRUint32 aCoordinateType, + nsIAccessNode *aAccessNode, + nsIntPoint *aCoords) +{ + NS_ENSURE_ARG_POINTER(aCoords); + + aCoords->MoveTo(aX, aY); + + switch (aCoordinateType) { + case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE: + break; + + case nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE: + { + NS_ENSURE_ARG(aAccessNode); + + nsCOMPtr DOMNode; + aAccessNode->GetDOMNode(getter_AddRefs(DOMNode)); + NS_ENSURE_STATE(DOMNode); + + nsIntPoint wndCoords = nsAccUtils::GetScreenCoordsForWindow(DOMNode); + *aCoords += wndCoords; + break; + } + + case nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE: + { + NS_ENSURE_ARG(aAccessNode); + + nsCOMPtr parent; + nsCOMPtr accessible(do_QueryInterface(aAccessNode)); + if (accessible) { + nsCOMPtr parentAccessible; + accessible->GetParent(getter_AddRefs(parentAccessible)); + parent = do_QueryInterface(parentAccessible); + } else { + nsCOMPtr parentAccessNode; + aAccessNode->GetParentNode(getter_AddRefs(parentAccessNode)); + parent = do_QueryInterface(parentAccessNode); + } + + NS_ENSURE_STATE(parent); + + nsIFrame *parentFrame = parent->GetFrame(); + NS_ENSURE_STATE(parentFrame); + + nsIntRect parentRect = parentFrame->GetScreenRectExternal(); + aCoords->x += parentRect.x; + aCoords->y += parentRect.y; + break; + } + + default: + return NS_ERROR_INVALID_ARG; + } + + return NS_OK; +} + nsIntPoint nsAccUtils::GetScreenCoordsForWindow(nsIDOMNode *aNode) { diff --git a/accessible/src/base/nsAccessibilityUtils.h b/accessible/src/base/nsAccessibilityUtils.h index fc6454c5cc4..e6da866238e 100755 --- a/accessible/src/base/nsAccessibilityUtils.h +++ b/accessible/src/base/nsAccessibilityUtils.h @@ -41,6 +41,7 @@ #include "nsAccessibilityAtoms.h" #include "nsIAccessible.h" +#include "nsIAccessNode.h" #include "nsARIAMap.h" #include "nsIDOMNode.h" @@ -162,6 +163,33 @@ public: nsIDOMNode *aEndNode, PRInt32 aEndIndex, PRUint32 aScrollType); + /** Helper method to scroll range into view, used for implementation of + * nsIAccessibleText::scrollSubstringTo[Point](). + * + * @param aFrame the frame for accessible the range belongs to. + * @param aStartNode start node of a range + * @param aStartOffset an offset inside the start node + * @param aEndNode end node of a range + * @param aEndOffset an offset inside the end node + * @param aVPercent how to align vertically, specified in percents + * @param aHPercent how to align horizontally, specified in percents + */ + static nsresult ScrollSubstringTo(nsIFrame *aFrame, + nsIDOMNode *aStartNode, PRInt32 aStartIndex, + nsIDOMNode *aEndNode, PRInt32 aEndIndex, + PRInt16 aVPercent, PRInt16 aHPercent); + + /** + * Scrolls the given frame to the point, used for implememntation of + * nsIAccessNode::scrollToPoint and nsIAccessibleText::scrollSubstringToPoint. + * + * @param aScrollableFrame the scrollable frame + * @param aFrame the frame to scroll + * @param aPoint the point scroll to + */ + static void ScrollFrameToPoint(nsIFrame *aScrollableFrame, + nsIFrame *aFrame, const nsIntPoint& aPoint); + /** * Converts scroll type constant defined in nsIAccessibleScrollType to * vertical and horizontal percents. @@ -170,6 +198,22 @@ public: PRInt16 *aVPercent, PRInt16 *aHPercent); + /** + * Converts the given coordinates to coordinates relative screen. + * + * @param aX [in] the given x coord + * @param aY [in] the given y coord + * @param aCoordinateType [in] specifies coordinates origin (refer to + * nsIAccessibleCoordinateType) + * @param aAccessNode [in] the accessible if coordinates are given + * relative it. + * @param aCoords [out] converted coordinates + */ + static nsresult ConvertToScreenCoords(PRInt32 aX, PRInt32 aY, + PRUint32 aCoordinateType, + nsIAccessNode *aAccessNode, + nsIntPoint *aCoords); + /** * Returns coordinates relative screen for the top level window. * diff --git a/accessible/src/html/Makefile.in b/accessible/src/html/Makefile.in index e717f00c375..77fc2e58846 100644 --- a/accessible/src/html/Makefile.in +++ b/accessible/src/html/Makefile.in @@ -61,6 +61,7 @@ REQUIRES = composer \ necko \ string \ thebes \ + view \ webshell \ widget \ xpcom \ diff --git a/accessible/src/html/nsHyperTextAccessible.cpp b/accessible/src/html/nsHyperTextAccessible.cpp index 98b2b171c9c..49e146d1b40 100644 --- a/accessible/src/html/nsHyperTextAccessible.cpp +++ b/accessible/src/html/nsHyperTextAccessible.cpp @@ -56,6 +56,7 @@ #include "nsIEditor.h" #include "nsIFontMetrics.h" #include "nsIFrame.h" +#include "nsIScrollableFrame.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIPlaintextEditor.h" #include "nsISelection2.h" @@ -665,6 +666,59 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI return NS_OK; } +nsresult +nsHyperTextAccessible::HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset, + PRInt32 aEndHTOffset, + nsIDOMNode **aStartNode, + PRInt32 *aStartOffset, + nsIDOMNode **aEndNode, + PRInt32 *aEndOffset) +{ + NS_ENSURE_ARG_POINTER(aStartNode); + *aStartNode = nsnull; + + NS_ENSURE_ARG_POINTER(aStartOffset); + *aStartOffset = -1; + + NS_ENSURE_ARG_POINTER(aEndNode); + *aEndNode = nsnull; + + NS_ENSURE_ARG_POINTER(aEndOffset); + *aEndOffset = -1; + + nsCOMPtr startAcc, endAcc; + PRInt32 startOffset = aStartHTOffset, endOffset = aEndHTOffset; + nsIFrame *startFrame = nsnull, *endFrame = nsnull; + + startFrame = GetPosAndText(startOffset, endOffset, nsnull, &endFrame, nsnull, + getter_AddRefs(startAcc), getter_AddRefs(endAcc)); + if (!startAcc || !endAcc) + return NS_ERROR_FAILURE; + + nsCOMPtr startNode, endNode; + nsresult rv = GetDOMPointByFrameOffset(startFrame, startOffset, startAcc, + getter_AddRefs(startNode), + &startOffset); + NS_ENSURE_SUCCESS(rv, rv); + + if (aStartHTOffset != aEndHTOffset) { + rv = GetDOMPointByFrameOffset(endFrame, endOffset, endAcc, + getter_AddRefs(endNode), &endOffset); + NS_ENSURE_SUCCESS(rv, rv); + } else { + endNode = startNode; + endOffset = startOffset; + } + + NS_ADDREF(*aStartNode = startNode); + *aStartOffset = startOffset; + + NS_ADDREF(*aEndNode = endNode); + *aEndOffset = endOffset; + + return NS_OK; +} + PRInt32 nsHyperTextAccessible::GetRelativeOffset(nsIPresShell *aPresShell, nsIFrame *aFromFrame, @@ -1572,13 +1626,17 @@ NS_IMETHODIMP nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, P /* * Changes the start and end offset of the specified selection. */ -NS_IMETHODIMP nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum, PRInt32 aStartOffset, PRInt32 aEndOffset) +NS_IMETHODIMP +nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum, + PRInt32 aStartOffset, + PRInt32 aEndOffset) { nsCOMPtr domSel; nsresult rv = GetSelections(nsnull, getter_AddRefs(domSel)); NS_ENSURE_SUCCESS(rv, rv); - PRInt32 isOnlyCaret = (aStartOffset == aEndOffset); // Caret is a collapsed selection + // Caret is a collapsed selection + PRBool isOnlyCaret = (aStartOffset == aEndOffset); PRInt32 rangeCount; domSel->GetRangeCount(&rangeCount); @@ -1595,78 +1653,20 @@ NS_IMETHODIMP nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum, P NS_ENSURE_TRUE(range, NS_ERROR_FAILURE); } - nsIFrame *endFrame; - nsCOMPtr startAcc, endAcc; - nsIFrame *startFrame = GetPosAndText(aStartOffset, aEndOffset, nsnull, &endFrame, nsnull, - getter_AddRefs(startAcc), getter_AddRefs(endAcc)); + PRInt32 startOffset, endOffset; + nsCOMPtr startNode, endNode; - nsCOMPtr shell = GetPresShell(); + rv = HypertextOffsetsToDOMRange(aStartOffset, aEndOffset, + getter_AddRefs(startNode), &startOffset, + getter_AddRefs(endNode), &endOffset); + NS_ENSURE_SUCCESS(rv, rv); - if (!startFrame) { // past the end of the hyper text - nsCOMPtr startAccessNode = do_QueryInterface(startAcc); - NS_ENSURE_TRUE(startAccessNode, NS_ERROR_FAILURE); - nsCOMPtr node; - startAccessNode->GetDOMNode(getter_AddRefs(node)); - NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - rv = range->SetStartAfter(node); - NS_ENSURE_SUCCESS(rv, rv); - } - else { - nsIContent *startParentContent = startFrame->GetContent(); - PRInt32 startOffset; - if (startFrame->GetType() != nsAccessibilityAtoms::textFrame) { - nsIContent *newParent = startParentContent->GetParent(); - startOffset = newParent->IndexOf(startParentContent); - startParentContent = newParent; - } - else { - // We have a rendered offset into the text frame, and it needs to be - // a content offset for us to set the caret - nsIFrame *startPrimaryFrame = - shell->GetPrimaryFrameFor(startFrame->GetContent()); - rv = RenderedToContentOffset(startPrimaryFrame, aStartOffset, &startOffset); - NS_ENSURE_SUCCESS(rv, rv); - } - nsCOMPtr startParentNode(do_QueryInterface(startParentContent)); - NS_ENSURE_TRUE(startParentNode, NS_ERROR_FAILURE); - rv = range->SetStart(startParentNode, startOffset); - NS_ENSURE_SUCCESS(rv, rv); - } + rv = range->SetStart(startNode, startOffset); + NS_ENSURE_SUCCESS(rv, rv); - if (isOnlyCaret) { - rv = range->Collapse(PR_TRUE); - NS_ENSURE_SUCCESS(rv, rv); - } - else if (!endFrame) { // past the end of the hyper text - nsCOMPtr endAccessNode = do_QueryInterface(endAcc); - NS_ENSURE_TRUE(endAccessNode, NS_ERROR_FAILURE); - nsCOMPtr node; - endAccessNode->GetDOMNode(getter_AddRefs(node)); - NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - rv = range->SetEndAfter(node); - NS_ENSURE_SUCCESS(rv, rv); - } - else { - nsIContent *endParentContent = endFrame->GetContent(); - PRInt32 endOffset; - if (endFrame->GetType() != nsAccessibilityAtoms::textFrame) { - nsIContent *newParent = endParentContent->GetParent(); - endOffset = newParent->IndexOf(endParentContent); - endParentContent = newParent; - } - else { - // We have a rendered offset into the text frame, and it needs to be - // a content offset for us to set the caret - nsIFrame *endPrimaryFrame = - shell->GetPrimaryFrameFor(endFrame->GetContent()); - rv = RenderedToContentOffset(endPrimaryFrame, aEndOffset, &endOffset); - NS_ENSURE_SUCCESS(rv, rv); - } - nsCOMPtr endParentNode(do_QueryInterface(endParentContent)); - NS_ENSURE_TRUE(endParentNode, NS_ERROR_FAILURE); - rv = range->SetEnd(endParentNode, endOffset); - NS_ENSURE_SUCCESS(rv, rv); - } + rv = isOnlyCaret ? range->Collapse(PR_TRUE) : + range->SetEnd(endNode, endOffset); + NS_ENSURE_SUCCESS(rv, rv); if (aSelectionNum == rangeCount) { // Add successfully created new range return domSel->AddRange(range); @@ -1708,56 +1708,96 @@ NS_IMETHODIMP nsHyperTextAccessible::RemoveSelection(PRInt32 aSelectionNum) return domSel->RemoveRange(range); } +// void nsIAccessibleText:: +// scrollSubstringTo(in long startIndex, in long endIndex, +// in unsigned long scrollType); NS_IMETHODIMP nsHyperTextAccessible::ScrollSubstringTo(PRInt32 aStartIndex, PRInt32 aEndIndex, PRUint32 aScrollType) { - PRInt32 startOffset = aStartIndex, endOffset = aEndIndex; - nsIFrame *startFrame = nsnull, *endFrame = nsnull; - nsCOMPtr startAcc, endAcc; + PRInt32 startOffset, endOffset; + nsCOMPtr startNode, endNode; - startFrame = GetPosAndText(startOffset, endOffset, - nsnull, &endFrame, nsnull, - getter_AddRefs(startAcc), getter_AddRefs(endAcc)); - if (!startFrame || !endFrame) - return NS_ERROR_FAILURE; - - nsCOMPtr startNode; - nsCOMPtr startContent(startFrame->GetContent()); - - if (startFrame->GetType() == nsAccessibilityAtoms::textFrame) { - nsresult rv = RenderedToContentOffset(startFrame, startOffset, - &startOffset); - NS_ENSURE_SUCCESS(rv, rv); - startNode = do_QueryInterface(startContent); - } else { - nsCOMPtr startParent(startContent->GetParent()); - NS_ENSURE_STATE(startParent); - startOffset = startParent->IndexOf(startContent); - startNode = do_QueryInterface(startParent); - } - NS_ENSURE_STATE(startNode); - - nsCOMPtr endNode; - nsCOMPtr endContent(endFrame->GetContent()); - - if (endFrame->GetType() == nsAccessibilityAtoms::textFrame) { - nsresult rv = RenderedToContentOffset(endFrame, endOffset, - &endOffset); - NS_ENSURE_SUCCESS(rv, rv); - endNode = do_QueryInterface(endContent); - } else { - nsCOMPtr endParent(endContent->GetParent()); - NS_ENSURE_STATE(endParent); - endOffset = endParent->IndexOf(endContent); - endNode = do_QueryInterface(endParent); - } - NS_ENSURE_STATE(endNode); + nsresult rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex, + getter_AddRefs(startNode), + &startOffset, + getter_AddRefs(endNode), + &endOffset); + NS_ENSURE_SUCCESS(rv, rv); return nsAccUtils::ScrollSubstringTo(GetFrame(), startNode, startOffset, endNode, endOffset, aScrollType); } +// void nsIAccessibleText:: +// scrollSubstringToPoint(in long startIndex, in long endIndex, +// in unsigned long coordinateType, +// in long x, in long y); +NS_IMETHODIMP +nsHyperTextAccessible::ScrollSubstringToPoint(PRInt32 aStartIndex, + PRInt32 aEndIndex, + PRUint32 aCoordinateType, + PRInt32 aX, PRInt32 aY) +{ + nsIFrame *frame = GetFrame(); + if (!frame) + return NS_ERROR_FAILURE; + + nsIntPoint coords; + nsresult rv = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType, + this, &coords); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt32 startOffset, endOffset; + nsCOMPtr startNode, endNode; + + rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex, + getter_AddRefs(startNode), &startOffset, + getter_AddRefs(endNode), &endOffset); + NS_ENSURE_SUCCESS(rv, rv); + + nsPresContext *presContext = frame->PresContext(); + + PRBool initialScrolled = PR_FALSE; + nsIFrame *parentFrame = frame; + while (parentFrame = parentFrame->GetParent()) { + nsIScrollableFrame *scrollableFrame = nsnull; + CallQueryInterface(parentFrame, &scrollableFrame); + if (scrollableFrame) { + if (!initialScrolled) { + // Scroll substring to the given point. Turn the point into percents + // relative scrollable area to use nsAccUtils::ScrollSubstringTo. + nsIntRect frameRect = parentFrame->GetScreenRectExternal(); + PRInt32 devOffsetX = coords.x - frameRect.x; + PRInt32 devOffsetY = coords.y - frameRect.y; + + nsPoint offsetPoint(presContext->DevPixelsToAppUnits(devOffsetX), + presContext->DevPixelsToAppUnits(devOffsetY)); + + nsSize size(parentFrame->GetSize()); + PRInt16 hPercent = offsetPoint.x * 100 / size.width; + PRInt16 vPercent = offsetPoint.y * 100 / size.height; + + rv = nsAccUtils::ScrollSubstringTo(GetFrame(), startNode, startOffset, + endNode, endOffset, + vPercent, hPercent); + NS_ENSURE_SUCCESS(rv, rv); + + initialScrolled = PR_TRUE; + } else { + // Substring was scrolled to the given point already inside its closest + // scrollable area. If there are nested scrollable areas then make + // sure we scroll lower areas to the given point inside currently + // traversed scrollable area. + nsAccUtils::ScrollFrameToPoint(parentFrame, frame, coords); + } + } + frame = parentFrame; + } + + return NS_OK; +} + nsresult nsHyperTextAccessible::ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset, PRUint32 *aRenderedOffset) { @@ -1803,4 +1843,58 @@ nsresult nsHyperTextAccessible::RenderedToContentOffset(nsIFrame *aFrame, PRUint return NS_OK; } +nsresult +nsHyperTextAccessible::GetDOMPointByFrameOffset(nsIFrame *aFrame, + PRInt32 aOffset, + nsIAccessible *aAccessible, + nsIDOMNode **aNode, + PRInt32 *aNodeOffset) +{ + NS_ENSURE_ARG(aAccessible); + + nsCOMPtr node; + + if (!aFrame) { + // If the given frame is null then set offset after the DOM node of the + // given accessible. + nsCOMPtr accessNode(do_QueryInterface(aAccessible)); + + nsCOMPtr DOMNode; + accessNode->GetDOMNode(getter_AddRefs(DOMNode)); + nsCOMPtr content(do_QueryInterface(DOMNode)); + NS_ENSURE_STATE(content); + + nsCOMPtr parent(content->GetParent()); + NS_ENSURE_STATE(parent); + + *aNodeOffset = parent->IndexOf(content) + 1; + node = do_QueryInterface(parent); + + } else if (aFrame->GetType() == nsAccessibilityAtoms::textFrame) { + nsCOMPtr content(aFrame->GetContent()); + NS_ENSURE_STATE(content); + + nsCOMPtr shell(GetPresShell()); + NS_ENSURE_STATE(shell); + + nsIFrame *primaryFrame = shell->GetPrimaryFrameFor(content); + nsresult rv = RenderedToContentOffset(primaryFrame, aOffset, aNodeOffset); + NS_ENSURE_SUCCESS(rv, rv); + + node = do_QueryInterface(content); + + } else { + nsCOMPtr content(aFrame->GetContent()); + NS_ENSURE_STATE(content); + + nsCOMPtr parent(content->GetParent()); + NS_ENSURE_STATE(parent); + + *aNodeOffset = parent->IndexOf(content); + node = do_QueryInterface(parent); + } + + NS_IF_ADDREF(*aNode = node); + return NS_OK; +} diff --git a/accessible/src/html/nsHyperTextAccessible.h b/accessible/src/html/nsHyperTextAccessible.h index 8d09a34c0e9..86e552da709 100644 --- a/accessible/src/html/nsHyperTextAccessible.h +++ b/accessible/src/html/nsHyperTextAccessible.h @@ -123,6 +123,23 @@ public: nsIAccessible **aFinalAccessible = nsnull, PRBool aIsEndOffset = PR_FALSE); + /** + * Turn a start and end hypertext offsets into DOM range. + * + * @param aStartHTOffset [in] the given start hypertext offset + * @param aEndHTOffset [in] the given end hypertext offset + * @param aStartNode [out] start node of the range + * @param aStartOffset [out] start offset of the range + * @param aEndNode [out] end node of the range + * @param aEndOffset [out] end offset of the range + */ + nsresult HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset, + PRInt32 aEndHTOffset, + nsIDOMNode **aStartNode, + PRInt32 *aStartOffset, + nsIDOMNode **aEndNode, + PRInt32 *aEndOffset); + protected: /* * This does the work for nsIAccessibleText::GetText[At|Before|After]Offset @@ -203,6 +220,11 @@ protected: nsISelection **aDomSel = nsnull, nsCOMArray* aRanges = nsnull); nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos); + + // Helpers + nsresult GetDOMPointByFrameOffset(nsIFrame *aFrame, PRInt32 aOffset, + nsIAccessible *aAccessible, + nsIDOMNode **aNode, PRInt32 *aNodeOffset); }; NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible, diff --git a/accessible/src/msaa/CAccessibleText.cpp b/accessible/src/msaa/CAccessibleText.cpp index 82ba452a7f4..6b3f55abb08 100755 --- a/accessible/src/msaa/CAccessibleText.cpp +++ b/accessible/src/msaa/CAccessibleText.cpp @@ -370,34 +370,18 @@ CAccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex, STDMETHODIMP CAccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex, - enum IA2CoordinateType aCoordinateType, + enum IA2CoordinateType aCoordType, long aX, long aY) { GET_NSIACCESSIBLETEXT - nsCOMPtr accessible; - PRInt32 startOffset = 0, endOffset = 0; + PRUint32 geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; - // XXX: aEndIndex isn't used. - textAcc->GetAttributeRange(aStartIndex, &startOffset, &endOffset, - getter_AddRefs(accessible)); - if (!accessible) - return E_FAIL; - - nsCOMPtr winAccessNode(do_QueryInterface(accessible)); - if (!winAccessNode) - return E_FAIL; - - void **instancePtr = 0; - winAccessNode->QueryNativeInterface(IID_IAccessible2, instancePtr); - if (!instancePtr) - return E_FAIL; - - IAccessible2 *pAccessible2 = static_cast(*instancePtr); - HRESULT hr = pAccessible2->scrollToPoint(aCoordinateType, aX, aY); - pAccessible2->Release(); - - return hr; + nsresult rv = textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex, + geckoCoordType, aX, aY); + return NS_FAILED(rv) ? E_FAIL : S_OK; } STDMETHODIMP diff --git a/accessible/src/msaa/nsAccessibleWrap.cpp b/accessible/src/msaa/nsAccessibleWrap.cpp index d108e310545..1b0ac8a5b73 100644 --- a/accessible/src/msaa/nsAccessibleWrap.cpp +++ b/accessible/src/msaa/nsAccessibleWrap.cpp @@ -1189,10 +1189,15 @@ nsAccessibleWrap::scrollTo(enum IA2ScrollType aScrollType) } STDMETHODIMP -nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType coordinateType, - long x, long y) +nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType aCoordType, + long aX, long aY) { - return E_NOTIMPL; + PRUint32 geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + return NS_SUCCEEDED(ScrollToPoint(geckoCoordType, aX, aY)) ? + S_OK : E_FAIL; } STDMETHODIMP