569 lines
19 KiB
C++
569 lines
19 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
|
|
* Portions created by Sun Microsystems are Copyright (C) 2002 Sun
|
|
* Microsystems, Inc. All Rights Reserved.
|
|
*
|
|
* Original Author: Kyle Yuan (kyle.yuan@sun.com)
|
|
|
|
* Contributor(s):
|
|
*
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the NPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "nsAccessibilityAtoms.h"
|
|
#include "nsAccessibilityService.h"
|
|
#include "nsAccessibleHyperText.h"
|
|
#include "nsHTMLLinkAccessibleWrap.h"
|
|
#include "nsHTMLTextAccessible.h"
|
|
#include "nsPIAccessNode.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsILink.h"
|
|
#include "nsIServiceManager.h"
|
|
|
|
/*
|
|
* nsAccessibleHyperText supports both nsIAccessibleHyperText and nsIAccessibleText.
|
|
* It's mainly aimed at the compound content that consists of many text nodes and links.
|
|
* Typically, it's a paragraph of text, a cell of table, etc.
|
|
*/
|
|
|
|
NS_IMPL_ISUPPORTS2(nsAccessibleHyperText, nsIAccessibleHyperText, nsIAccessibleText)
|
|
|
|
nsAccessibleHyperText::nsAccessibleHyperText(nsIDOMNode* aDomNode, nsIWeakReference* aShell)
|
|
{
|
|
mIndex = -1;
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aDomNode));
|
|
if (content) {
|
|
nsCOMPtr<nsIContent> parentContent = content->GetParent();
|
|
if (parentContent)
|
|
mIndex = parentContent->IndexOf(content);
|
|
}
|
|
|
|
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aShell));
|
|
if (shell) {
|
|
NS_NewArray(getter_AddRefs(mTextChildren));
|
|
if (mTextChildren) {
|
|
nsIFrame *frame = nsnull;
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aDomNode));
|
|
shell->GetPrimaryFrameFor(content, &frame);
|
|
nsIFrame *parentFrame = nsAccessible::GetParentBlockFrame(frame);
|
|
NS_ASSERTION(parentFrame, "Error: HyperText can't get parent block frame");
|
|
if (parentFrame) {
|
|
nsIFrame* childFrame = parentFrame->GetFirstChild(nsnull);
|
|
PRBool bSave = PR_FALSE;
|
|
GetAllTextChildren(shell->GetPresContext(), childFrame,
|
|
aDomNode, bSave);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void nsAccessibleHyperText::Shutdown()
|
|
{
|
|
mTextChildren = nsnull;
|
|
}
|
|
|
|
PRBool nsAccessibleHyperText::GetAllTextChildren(nsPresContext *aPresContext, nsIFrame *aCurFrame, nsIDOMNode* aNode, PRBool &bSave)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, PR_FALSE);
|
|
|
|
while (aCurFrame) {
|
|
|
|
nsIAtom* frameType = aCurFrame->GetType();
|
|
if (frameType == nsAccessibilityAtoms::blockFrame) {
|
|
if (bSave)
|
|
return PR_TRUE;
|
|
}
|
|
else {
|
|
if (frameType == nsAccessibilityAtoms::textFrame) {
|
|
// Skip the empty text frames that usually only consist of "\n"
|
|
if (! aCurFrame->GetRect().IsEmpty()) {
|
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aCurFrame->GetContent()));
|
|
if (bSave || node == aNode) {
|
|
#ifdef DEBUG
|
|
nsAutoString text;
|
|
node->GetNodeValue(text);
|
|
char buf[1024];
|
|
text.ToCString(buf, sizeof(buf));
|
|
#endif
|
|
// some long text node may be divided into several frames,
|
|
// so we must check whether this node is already in the array
|
|
PRUint32 index;
|
|
nsresult rv = mTextChildren->IndexOf(0, node, &index);
|
|
if (NS_FAILED(rv)) {
|
|
mTextChildren->AppendElement(node, PR_FALSE);
|
|
}
|
|
bSave = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
nsIFrame* childFrame = aCurFrame->GetFirstChild(nsnull);
|
|
if (GetAllTextChildren(aPresContext, childFrame, aNode, bSave))
|
|
return PR_TRUE;
|
|
}
|
|
|
|
nsIFrame* siblingFrame = aCurFrame->GetNextSibling();
|
|
aCurFrame = siblingFrame;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRInt32 nsAccessibleHyperText::GetIndex()
|
|
// XXX, this index is used for giving a hypertext a meaningful name, such as "Paragraph n",
|
|
// but by now, we haven't found a better way to do that, just use the index of our parent's
|
|
// children list as the number.
|
|
{
|
|
return mIndex;
|
|
}
|
|
|
|
nsIDOMNode* nsAccessibleHyperText::FindTextNodeByOffset(PRInt32 aOffset, PRInt32& aBeforeLength)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, nsnull);
|
|
|
|
aBeforeLength = 0;
|
|
|
|
PRUint32 index, count;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsAccessibleText accText(domNode);
|
|
PRInt32 charCount;
|
|
if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount))) {
|
|
if (aOffset >= 0 && aOffset <= charCount) {
|
|
return domNode;
|
|
}
|
|
aOffset -= charCount;
|
|
aBeforeLength += charCount;
|
|
}
|
|
}
|
|
|
|
return nsnull;
|
|
}
|
|
|
|
nsresult nsAccessibleHyperText::GetTextHelper(EGetTextType aType, nsAccessibleTextBoundary aBoundaryType,
|
|
PRInt32 aOffset, PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
|
|
{
|
|
PRInt32 beforeLength;
|
|
nsIDOMNode* domNode = FindTextNodeByOffset(aOffset, beforeLength);
|
|
if (domNode) {
|
|
nsAccessibleText accText(domNode);
|
|
// call nsAccessibleText::GetTextHelper directly so that it can adjust the aStartOffset/aEndOffset
|
|
// according to the mTextChildren
|
|
nsresult rv = accText.GetTextHelper(aType, aBoundaryType, aOffset - beforeLength, aStartOffset, aEndOffset, mTextChildren, aText);
|
|
return rv;
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
// ------- nsIAccessibleText ---------------
|
|
/* attribute long caretOffset; */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetCaretOffset(PRInt32 *aCaretOffset)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
*aCaretOffset = 0;
|
|
|
|
PRInt32 charCount, caretOffset;
|
|
PRUint32 index, count;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsAccessibleText accText(domNode);
|
|
if (NS_SUCCEEDED(accText.GetCaretOffset(&caretOffset))) {
|
|
*aCaretOffset += caretOffset;
|
|
return NS_OK;
|
|
} else if (GetLinkNode(domNode) == nsAccessNode::gLastFocusedNode) {
|
|
//Focus is here
|
|
return NS_OK;
|
|
}
|
|
if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount))) {
|
|
*aCaretOffset += charCount;
|
|
}
|
|
}
|
|
|
|
// The current focus node is not inside us
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP nsAccessibleHyperText::SetCaretOffset(PRInt32 aCaretOffset)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
PRInt32 beforeLength;
|
|
nsIDOMNode* domNode = FindTextNodeByOffset(aCaretOffset, beforeLength);
|
|
if (domNode) {
|
|
nsAccessibleText accText(domNode);
|
|
return accText.SetCaretOffset(aCaretOffset - beforeLength);
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
/* readonly attribute long characterCount; */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetCharacterCount(PRInt32 *aCharacterCount)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
*aCharacterCount = 0;
|
|
|
|
PRInt32 charCount;
|
|
PRUint32 index, count;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsAccessibleText accText(domNode);
|
|
if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount)))
|
|
*aCharacterCount += charCount;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute long selectionCount; */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetSelectionCount(PRInt32 *aSelectionCount)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
*aSelectionCount = 0;
|
|
|
|
PRInt32 selCount;
|
|
PRUint32 index, count;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsAccessibleText accText(domNode);
|
|
if (NS_SUCCEEDED(accText.GetSelectionCount(&selCount)))
|
|
*aSelectionCount += selCount;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* AString getText (in long startOffset, in long endOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetText(PRInt32 aStartOffset, PRInt32 aEndOffset, nsAString & aText)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
if (aEndOffset == -1)
|
|
GetCharacterCount(&aEndOffset);
|
|
|
|
PRInt32 charCount, totalCount = 0, currentStart, currentEnd;
|
|
PRUint32 index, count;
|
|
nsAutoString text, nodeText;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsAccessibleText accText(domNode);
|
|
if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount))) {
|
|
currentStart = aStartOffset - totalCount;
|
|
currentEnd = aEndOffset - totalCount;
|
|
if (currentStart >= 0 && currentStart < charCount) {
|
|
accText.GetText(currentStart, NS_MIN(charCount, currentEnd), nodeText);
|
|
text += nodeText;
|
|
aStartOffset += charCount - currentStart;
|
|
if (aStartOffset >= aEndOffset)
|
|
break;
|
|
}
|
|
totalCount += charCount;
|
|
}
|
|
}
|
|
|
|
// Eliminate the new line character
|
|
PRInt32 start = 0, length = text.Length();
|
|
PRInt32 offset = text.FindCharInSet("\n\r");
|
|
while (offset != kNotFound) {
|
|
if (offset > start)
|
|
aText += Substring(text, start, offset - start);
|
|
|
|
start = offset + 1;
|
|
offset = text.FindCharInSet("\n\r", start);
|
|
}
|
|
// Consume the last bit of the string if there's any left
|
|
if (start < length) {
|
|
if (start)
|
|
aText += Substring(text, start, length - start);
|
|
else
|
|
aText = text;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* AString getTextBeforeOffset (in long offset, in nsAccessibleTextBoundary boundaryType, out long startOffset, out long endOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetTextBeforeOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
|
|
PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
|
|
{
|
|
return GetTextHelper(eGetBefore, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
|
|
}
|
|
|
|
/* AString getTextAfterOffset (in long offset, in nsAccessibleTextBoundary boundaryType, out long startOffset, out long endOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetTextAfterOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
|
|
PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
|
|
{
|
|
return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
|
|
}
|
|
|
|
/* AString getTextAtOffset (in long offset, in nsAccessibleTextBoundary boundaryType, out long startOffset, out long endOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetTextAtOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
|
|
PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
|
|
{
|
|
return GetTextHelper(eGetAt, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
|
|
}
|
|
|
|
/* wchar getCharacterAtOffset (in long offset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetCharacterAtOffset(PRInt32 aOffset, PRUnichar *aCharacter)
|
|
{
|
|
PRInt32 beforeLength;
|
|
nsIDOMNode* domNode = FindTextNodeByOffset(aOffset, beforeLength);
|
|
if (domNode) {
|
|
nsAccessibleText accText(domNode);
|
|
return accText.GetCharacterAtOffset(aOffset - beforeLength, aCharacter);
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
/* nsISupports getAttributeRange (in long offset, out long rangeStartOffset, out long rangeEndOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetAttributeRange(PRInt32 aOffset, PRInt32 *aRangeStartOffset, PRInt32 *aRangeEndOffset, nsISupports **aAttributes)
|
|
{
|
|
*aRangeStartOffset = aOffset;
|
|
GetCharacterCount(aRangeEndOffset);
|
|
*aAttributes = 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void getCharacterExtents (in long offset, out long x, out long y, out long width, out long height, in nsAccessibleCoordType coordType); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetCharacterExtents(PRInt32 aOffset, PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight, nsAccessibleCoordType aCoordType)
|
|
{
|
|
PRInt32 beforeLength;
|
|
nsIDOMNode* domNode = FindTextNodeByOffset(aOffset, beforeLength);
|
|
if (domNode) {
|
|
nsAccessibleText accText(domNode);
|
|
return accText.GetCharacterExtents(aOffset - beforeLength, aX, aY, aWidth, aHeight, aCoordType);
|
|
}
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
/* long getOffsetAtPoint (in long x, in long y, in nsAccessibleCoordType coordType); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetOffsetAtPoint(PRInt32 aX, PRInt32 aY, nsAccessibleCoordType aCoordType, PRInt32 *aOffset)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* void getSelectionBounds (in long selectionNum, out long startOffset, out long endOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetSelectionBounds(PRInt32 aSelectionNum, PRInt32 *aStartOffset, PRInt32 *aEndOffset)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* void setSelectionBounds (in long selectionNum, in long startOffset, in long endOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::SetSelectionBounds(PRInt32 aSelectionNum, PRInt32 aStartOffset, PRInt32 aEndOffset)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* void addSelection (in long startOffset, in long endOffset); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::AddSelection(PRInt32 aStartOffset, PRInt32 aEndOffset)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* void removeSelection (in long selectionNum); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::RemoveSelection(PRInt32 aSelectionNum)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
// ------- nsIAccessibleHyperText ---------------
|
|
/* readonly attribute long links; */NS_IMETHODIMP nsAccessibleHyperText::GetLinks(PRInt32 *aLinks)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
*aLinks = 0;
|
|
|
|
PRUint32 index, count;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
if (GetLinkNode(domNode)) {
|
|
(*aLinks)++;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* nsIAccessibleHyperLink getLink (in long index); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetLink(PRInt32 aIndex, nsIAccessibleHyperLink **aLink)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
PRUint32 index, count, linkCount = 0;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsIDOMNode* parentNode = GetLinkNode(domNode);
|
|
if (parentNode) {
|
|
if (linkCount++ == NS_STATIC_CAST(PRUint32, aIndex)) {
|
|
nsCOMPtr<nsIWeakReference> weakShell;
|
|
nsAccessibilityService::GetShellFromNode(parentNode, getter_AddRefs(weakShell));
|
|
NS_ENSURE_TRUE(weakShell, NS_ERROR_FAILURE);
|
|
|
|
// Check to see if we already have it in the cache.
|
|
nsCOMPtr<nsIAccessibilityService>
|
|
accService(do_GetService("@mozilla.org/accessibilityService;1"));
|
|
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsIAccessible> cachedAcc;
|
|
nsresult rv = accService->GetCachedAccessible(parentNode, weakShell,
|
|
getter_AddRefs(cachedAcc));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
*aLink = nsnull;
|
|
if (cachedAcc) {
|
|
// Retrieved from cache
|
|
nsCOMPtr<nsIAccessibleHyperLink> cachedLink(do_QueryInterface(cachedAcc));
|
|
if (cachedLink) {
|
|
*aLink = cachedLink;
|
|
NS_IF_ADDREF(*aLink);
|
|
}
|
|
}
|
|
if (!(*aLink)) {
|
|
*aLink = new nsHTMLLinkAccessibleWrap(parentNode, mTextChildren, weakShell, nsnull);
|
|
NS_ENSURE_TRUE(*aLink, NS_ERROR_OUT_OF_MEMORY);
|
|
NS_ADDREF(*aLink);
|
|
nsCOMPtr<nsPIAccessNode> accessNode(do_QueryInterface(*aLink));
|
|
accessNode->Init();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* long getLinkIndex (in long charIndex); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetLinkIndex(PRInt32 aCharIndex, PRInt32 *aLinkIndex)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
*aLinkIndex = -1;
|
|
PRInt32 beforeLength_unused;
|
|
PRUint32 nodeIndex;
|
|
nsIDOMNode* domNode = FindTextNodeByOffset(aCharIndex, beforeLength_unused);
|
|
if (GetLinkNode(domNode)
|
|
&& NS_SUCCEEDED(mTextChildren->IndexOf(0, domNode, &nodeIndex))) {
|
|
(*aLinkIndex)++;
|
|
for (PRUint32 index = 0; index < nodeIndex; index++) {
|
|
nsCOMPtr<nsIDOMNode> childNode(do_QueryElementAt(mTextChildren, index));
|
|
if (GetLinkNode(childNode)) {
|
|
(*aLinkIndex)++;
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/* long getSelectedLinkIndex (); */
|
|
NS_IMETHODIMP nsAccessibleHyperText::GetSelectedLinkIndex(PRInt32 *aSelectedLinkIndex)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
*aSelectedLinkIndex = -1;
|
|
|
|
PRUint32 count;
|
|
mTextChildren->GetLength(&count);
|
|
if (count <= 0)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode(do_QueryElementAt(mTextChildren, 0));
|
|
|
|
PRUint32 index, linkCount = 0;
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsIDOMNode* linkNode = GetLinkNode(domNode);
|
|
if (linkNode) {
|
|
if (linkNode == nsAccessNode::gLastFocusedNode) {
|
|
*aSelectedLinkIndex = linkCount;
|
|
return NS_OK;
|
|
}
|
|
linkCount++;
|
|
}
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult nsAccessibleHyperText::GetBounds(nsIWeakReference *aWeakShell, PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
|
|
{
|
|
NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
|
|
|
|
*x = *y = *width = *height = 0;
|
|
|
|
nsRect unionRectTwips;
|
|
PRUint32 index, count;
|
|
mTextChildren->GetLength(&count);
|
|
for (index = 0; index < count; index++) {
|
|
nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
|
|
nsHTMLTextAccessible *accText = new nsHTMLTextAccessible(domNode, aWeakShell, nsnull);
|
|
if (!accText)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsRect frameRect;
|
|
accText->GetBounds(&frameRect.x, &frameRect.y, &frameRect.width, &frameRect.height);
|
|
unionRectTwips.UnionRect(unionRectTwips, frameRect);
|
|
delete accText;
|
|
}
|
|
|
|
*x = unionRectTwips.x;
|
|
*y = unionRectTwips.y;
|
|
*width = unionRectTwips.width;
|
|
*height = unionRectTwips.height;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIDOMNode* nsAccessibleHyperText::GetLinkNode(nsIDOMNode* aNode)
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parentNode;
|
|
nsCOMPtr<nsILink> link;
|
|
while (aNode && link == nsnull) {
|
|
// text node maybe a child (or grandchild, ...) of a link node
|
|
aNode->GetParentNode(getter_AddRefs(parentNode));
|
|
aNode = parentNode;
|
|
link = do_QueryInterface(parentNode);
|
|
}
|
|
|
|
return parentNode;
|
|
}
|