Back to index

lightning-sunbird  0.9+nobinonly
nsAccessibleHyperText.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public
00006  * License Version 1.1 (the "License"); you may not use this file
00007  * except in compliance with the License. You may obtain a copy of
00008  * the License at http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS
00011  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00012  * implied. See the License for the specific language governing
00013  * rights and limitations under the License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
00018  * Portions created by Sun Microsystems are Copyright (C) 2002 Sun
00019  * Microsystems, Inc. All Rights Reserved.
00020  *
00021  * Original Author: Kyle Yuan (kyle.yuan@sun.com)
00022 
00023  * Contributor(s):
00024  *
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the NPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the NPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsAccessibilityAtoms.h"
00041 #include "nsAccessibilityService.h"
00042 #include "nsAccessibleHyperText.h"
00043 #include "nsHTMLLinkAccessibleWrap.h"
00044 #include "nsHTMLTextAccessible.h"
00045 #include "nsPIAccessNode.h"
00046 #include "nsIFrame.h"
00047 #include "nsILink.h"
00048 #include "nsIServiceManager.h"
00049 
00050 /*
00051  * nsAccessibleHyperText supports both nsIAccessibleHyperText and nsIAccessibleText.
00052  *   It's mainly aimed at the compound content that consists of many text nodes and links.
00053  *   Typically, it's a paragraph of text, a cell of table, etc.
00054 */
00055 
00056 NS_IMPL_ISUPPORTS2(nsAccessibleHyperText, nsIAccessibleHyperText, nsIAccessibleText)
00057 
00058 nsAccessibleHyperText::nsAccessibleHyperText(nsIDOMNode* aDomNode, nsIWeakReference* aShell)
00059 {
00060   mIndex = -1;
00061   nsCOMPtr<nsIContent> content(do_QueryInterface(aDomNode));
00062   if (content) {
00063     nsCOMPtr<nsIContent> parentContent = content->GetParent();
00064     if (parentContent)
00065       mIndex = parentContent->IndexOf(content);
00066   }
00067 
00068   nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aShell));
00069   if (shell) {
00070     NS_NewArray(getter_AddRefs(mTextChildren));
00071     if (mTextChildren) {
00072       nsIFrame *frame = nsnull;
00073       nsCOMPtr<nsIContent> content(do_QueryInterface(aDomNode));
00074       shell->GetPrimaryFrameFor(content, &frame);
00075       nsIFrame *parentFrame = nsAccessible::GetParentBlockFrame(frame);
00076       NS_ASSERTION(parentFrame, "Error: HyperText can't get parent block frame");
00077       if (parentFrame) {
00078         nsIFrame* childFrame = parentFrame->GetFirstChild(nsnull);
00079         PRBool bSave = PR_FALSE;
00080         GetAllTextChildren(shell->GetPresContext(), childFrame,
00081                            aDomNode, bSave);
00082       }
00083     }
00084   }
00085 }
00086 
00087 void nsAccessibleHyperText::Shutdown()
00088 {
00089   mTextChildren = nsnull;
00090 }
00091 
00092 PRBool nsAccessibleHyperText::GetAllTextChildren(nsPresContext *aPresContext, nsIFrame *aCurFrame, nsIDOMNode* aNode, PRBool &bSave)
00093 {
00094   NS_ENSURE_TRUE(mTextChildren, PR_FALSE);
00095 
00096   while (aCurFrame) {
00097 
00098     nsIAtom* frameType = aCurFrame->GetType();
00099     if (frameType == nsAccessibilityAtoms::blockFrame) {
00100       if (bSave)
00101         return PR_TRUE;
00102     }
00103     else {
00104       if (frameType == nsAccessibilityAtoms::textFrame) {
00105         // Skip the empty text frames that usually only consist of "\n"
00106         if (! aCurFrame->GetRect().IsEmpty()) {
00107           nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aCurFrame->GetContent()));
00108           if (bSave || node == aNode) {
00109 #ifdef DEBUG
00110             nsAutoString text;
00111             node->GetNodeValue(text);
00112             char buf[1024];
00113             text.ToCString(buf, sizeof(buf));
00114 #endif
00115             // some long text node may be divided into several frames, 
00116             // so we must check whether this node is already in the array
00117             PRUint32 index;
00118             nsresult rv = mTextChildren->IndexOf(0, node, &index);
00119             if (NS_FAILED(rv)) {
00120               mTextChildren->AppendElement(node, PR_FALSE);
00121             }
00122             bSave = PR_TRUE;
00123           }
00124         }
00125       }
00126 
00127       nsIFrame* childFrame = aCurFrame->GetFirstChild(nsnull);
00128       if (GetAllTextChildren(aPresContext, childFrame, aNode, bSave))
00129         return PR_TRUE;
00130     }
00131 
00132     nsIFrame* siblingFrame = aCurFrame->GetNextSibling();
00133     aCurFrame = siblingFrame;
00134   }
00135   return PR_FALSE;
00136 }
00137 
00138 PRInt32 nsAccessibleHyperText::GetIndex()
00139 // XXX, this index is used for giving a hypertext a meaningful name, such as "Paragraph n",
00140 // but by now, we haven't found a better way to do that, just use the index of our parent's
00141 // children list as the number.
00142 {
00143   return mIndex;
00144 }
00145 
00146 nsIDOMNode* nsAccessibleHyperText::FindTextNodeByOffset(PRInt32 aOffset, PRInt32& aBeforeLength)
00147 {
00148   NS_ENSURE_TRUE(mTextChildren, nsnull);
00149 
00150   aBeforeLength = 0;
00151 
00152   PRUint32 index, count;
00153   mTextChildren->GetLength(&count);
00154   for (index = 0; index < count; index++) {
00155     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00156     nsAccessibleText accText(domNode);
00157     PRInt32 charCount;
00158     if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount))) {
00159       if (aOffset >= 0 && aOffset <= charCount) {
00160         return domNode;
00161       }
00162       aOffset -= charCount;
00163       aBeforeLength += charCount;
00164     }
00165   }
00166 
00167   return nsnull;
00168 }
00169 
00170 nsresult nsAccessibleHyperText::GetTextHelper(EGetTextType aType, nsAccessibleTextBoundary aBoundaryType,
00171                                               PRInt32 aOffset, PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
00172 {
00173   PRInt32 beforeLength;
00174   nsIDOMNode* domNode = FindTextNodeByOffset(aOffset, beforeLength);
00175   if (domNode) {
00176     nsAccessibleText accText(domNode);
00177     // call nsAccessibleText::GetTextHelper directly so that it can adjust the aStartOffset/aEndOffset
00178     // according to the mTextChildren
00179     nsresult rv = accText.GetTextHelper(aType, aBoundaryType, aOffset - beforeLength, aStartOffset, aEndOffset, mTextChildren, aText);
00180     return rv;
00181   }
00182 
00183   return NS_ERROR_INVALID_ARG;
00184 }
00185 
00186 // ------- nsIAccessibleText ---------------
00187 /* attribute long caretOffset; */
00188 NS_IMETHODIMP nsAccessibleHyperText::GetCaretOffset(PRInt32 *aCaretOffset)
00189 {
00190   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00191 
00192   *aCaretOffset = 0;
00193 
00194   PRInt32 charCount, caretOffset;
00195   PRUint32 index, count;
00196   mTextChildren->GetLength(&count);
00197   for (index = 0; index < count; index++) {
00198     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00199     nsAccessibleText accText(domNode);
00200     if (NS_SUCCEEDED(accText.GetCaretOffset(&caretOffset))) {
00201       *aCaretOffset += caretOffset;
00202       return NS_OK;
00203     } else if (GetLinkNode(domNode) == nsAccessNode::gLastFocusedNode) {
00204       //Focus is here
00205       return NS_OK;
00206     }
00207     if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount))) {
00208       *aCaretOffset += charCount;
00209     }
00210   }
00211 
00212   // The current focus node is not inside us
00213   return NS_ERROR_FAILURE;
00214 }
00215 
00216 NS_IMETHODIMP nsAccessibleHyperText::SetCaretOffset(PRInt32 aCaretOffset)
00217 {
00218   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00219 
00220   PRInt32 beforeLength;
00221   nsIDOMNode* domNode = FindTextNodeByOffset(aCaretOffset, beforeLength);
00222   if (domNode) {
00223     nsAccessibleText accText(domNode);
00224     return accText.SetCaretOffset(aCaretOffset - beforeLength);
00225   }
00226 
00227   return NS_ERROR_INVALID_ARG;
00228 }
00229 
00230 /* readonly attribute long characterCount; */
00231 NS_IMETHODIMP nsAccessibleHyperText::GetCharacterCount(PRInt32 *aCharacterCount)
00232 {
00233   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00234 
00235   *aCharacterCount = 0;
00236 
00237   PRInt32 charCount;
00238   PRUint32 index, count;
00239   mTextChildren->GetLength(&count);
00240   for (index = 0; index < count; index++) {
00241     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00242     nsAccessibleText accText(domNode);
00243     if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount)))
00244       *aCharacterCount += charCount;
00245   }
00246 
00247   return NS_OK;
00248 }
00249 
00250 /* readonly attribute long selectionCount; */
00251 NS_IMETHODIMP nsAccessibleHyperText::GetSelectionCount(PRInt32 *aSelectionCount)
00252 {
00253   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00254 
00255   *aSelectionCount = 0;
00256 
00257   PRInt32 selCount;
00258   PRUint32 index, count;
00259   mTextChildren->GetLength(&count);
00260   for (index = 0; index < count; index++) {
00261     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00262     nsAccessibleText accText(domNode);
00263     if (NS_SUCCEEDED(accText.GetSelectionCount(&selCount)))
00264       *aSelectionCount += selCount;
00265   }
00266 
00267   return NS_OK;
00268 }
00269 
00270 /* AString getText (in long startOffset, in long endOffset); */
00271 NS_IMETHODIMP nsAccessibleHyperText::GetText(PRInt32 aStartOffset, PRInt32 aEndOffset, nsAString & aText)
00272 {
00273   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00274 
00275   if (aEndOffset == -1)
00276     GetCharacterCount(&aEndOffset);
00277 
00278   PRInt32 charCount, totalCount = 0, currentStart, currentEnd;
00279   PRUint32 index, count;
00280   nsAutoString text, nodeText;
00281   mTextChildren->GetLength(&count);
00282   for (index = 0; index < count; index++) {
00283     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00284     nsAccessibleText accText(domNode);
00285     if (NS_SUCCEEDED(accText.GetCharacterCount(&charCount))) {
00286       currentStart = aStartOffset - totalCount;
00287       currentEnd = aEndOffset - totalCount;
00288       if (currentStart >= 0 && currentStart < charCount) {
00289         accText.GetText(currentStart, NS_MIN(charCount, currentEnd), nodeText);
00290         text += nodeText;
00291         aStartOffset += charCount - currentStart;
00292         if (aStartOffset >= aEndOffset)
00293           break;
00294       }
00295       totalCount += charCount;
00296     }
00297   }
00298 
00299   // Eliminate the new line character
00300   PRInt32 start = 0, length = text.Length();
00301   PRInt32 offset = text.FindCharInSet("\n\r");
00302   while (offset != kNotFound) {
00303     if (offset > start)
00304       aText += Substring(text, start, offset - start);
00305 
00306     start = offset + 1;
00307     offset = text.FindCharInSet("\n\r", start);
00308   }
00309   // Consume the last bit of the string if there's any left
00310   if (start < length) {
00311     if (start)
00312       aText += Substring(text, start, length - start);
00313     else
00314       aText = text;
00315   }
00316 
00317   return NS_OK;
00318 }
00319 
00320 /* AString getTextBeforeOffset (in long offset, in nsAccessibleTextBoundary boundaryType, out long startOffset, out long endOffset); */
00321 NS_IMETHODIMP nsAccessibleHyperText::GetTextBeforeOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
00322                                                          PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
00323 {
00324   return GetTextHelper(eGetBefore, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
00325 }
00326 
00327 /* AString getTextAfterOffset (in long offset, in nsAccessibleTextBoundary boundaryType, out long startOffset, out long endOffset); */
00328 NS_IMETHODIMP nsAccessibleHyperText::GetTextAfterOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
00329                                                         PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
00330 {
00331   return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
00332 }
00333 
00334 /* AString getTextAtOffset (in long offset, in nsAccessibleTextBoundary boundaryType, out long startOffset, out long endOffset); */
00335 NS_IMETHODIMP nsAccessibleHyperText::GetTextAtOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
00336                                                      PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
00337 {
00338   return GetTextHelper(eGetAt, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
00339 }
00340 
00341 /* wchar getCharacterAtOffset (in long offset); */
00342 NS_IMETHODIMP nsAccessibleHyperText::GetCharacterAtOffset(PRInt32 aOffset, PRUnichar *aCharacter)
00343 {
00344   PRInt32 beforeLength;
00345   nsIDOMNode* domNode = FindTextNodeByOffset(aOffset, beforeLength);
00346   if (domNode) {
00347     nsAccessibleText accText(domNode);
00348     return accText.GetCharacterAtOffset(aOffset - beforeLength, aCharacter);
00349   }
00350 
00351   return NS_ERROR_INVALID_ARG;
00352 }
00353 
00354 /* nsISupports getAttributeRange (in long offset, out long rangeStartOffset, out long rangeEndOffset); */
00355 NS_IMETHODIMP nsAccessibleHyperText::GetAttributeRange(PRInt32 aOffset, PRInt32 *aRangeStartOffset, PRInt32 *aRangeEndOffset, nsISupports **aAttributes)
00356 {
00357   *aRangeStartOffset = aOffset;
00358   GetCharacterCount(aRangeEndOffset);
00359   *aAttributes = 0;
00360   return NS_OK;
00361 }
00362 
00363 /* void getCharacterExtents (in long offset, out long x, out long y, out long width, out long height, in nsAccessibleCoordType coordType); */
00364 NS_IMETHODIMP nsAccessibleHyperText::GetCharacterExtents(PRInt32 aOffset, PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight, nsAccessibleCoordType aCoordType)
00365 {
00366   PRInt32 beforeLength;
00367   nsIDOMNode* domNode = FindTextNodeByOffset(aOffset, beforeLength);
00368   if (domNode) {
00369     nsAccessibleText accText(domNode);
00370     return accText.GetCharacterExtents(aOffset - beforeLength, aX, aY, aWidth, aHeight, aCoordType);
00371   }
00372 
00373   return NS_ERROR_INVALID_ARG;
00374 }
00375 
00376 /* long getOffsetAtPoint (in long x, in long y, in nsAccessibleCoordType coordType); */
00377 NS_IMETHODIMP nsAccessibleHyperText::GetOffsetAtPoint(PRInt32 aX, PRInt32 aY, nsAccessibleCoordType aCoordType, PRInt32 *aOffset)
00378 {
00379   return NS_ERROR_NOT_IMPLEMENTED;
00380 }
00381 
00382 /* void getSelectionBounds (in long selectionNum, out long startOffset, out long endOffset); */
00383 NS_IMETHODIMP nsAccessibleHyperText::GetSelectionBounds(PRInt32 aSelectionNum, PRInt32 *aStartOffset, PRInt32 *aEndOffset)
00384 {
00385   return NS_ERROR_NOT_IMPLEMENTED;
00386 }
00387 
00388 /* void setSelectionBounds (in long selectionNum, in long startOffset, in long endOffset); */
00389 NS_IMETHODIMP nsAccessibleHyperText::SetSelectionBounds(PRInt32 aSelectionNum, PRInt32 aStartOffset, PRInt32 aEndOffset)
00390 {
00391   return NS_ERROR_NOT_IMPLEMENTED;
00392 }
00393 
00394 /* void addSelection (in long startOffset, in long endOffset); */
00395 NS_IMETHODIMP nsAccessibleHyperText::AddSelection(PRInt32 aStartOffset, PRInt32 aEndOffset)
00396 {
00397   return NS_ERROR_NOT_IMPLEMENTED;
00398 }
00399 
00400 /* void removeSelection (in long selectionNum); */
00401 NS_IMETHODIMP nsAccessibleHyperText::RemoveSelection(PRInt32 aSelectionNum)
00402 {
00403   return NS_ERROR_NOT_IMPLEMENTED;
00404 }
00405 
00406 // ------- nsIAccessibleHyperText ---------------
00407 /* readonly attribute long links; */NS_IMETHODIMP nsAccessibleHyperText::GetLinks(PRInt32 *aLinks)
00408 {
00409   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00410 
00411   *aLinks = 0;
00412 
00413   PRUint32 index, count;
00414   mTextChildren->GetLength(&count);
00415   for (index = 0; index < count; index++) {
00416     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00417     if (GetLinkNode(domNode)) {
00418       (*aLinks)++;
00419     }
00420   }
00421 
00422   return NS_OK;
00423 }
00424 
00425 /* nsIAccessibleHyperLink getLink (in long index); */
00426 NS_IMETHODIMP nsAccessibleHyperText::GetLink(PRInt32 aIndex, nsIAccessibleHyperLink **aLink)
00427 {
00428   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00429 
00430   PRUint32 index, count, linkCount = 0;
00431   mTextChildren->GetLength(&count);
00432   for (index = 0; index < count; index++) {
00433     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00434     nsIDOMNode* parentNode = GetLinkNode(domNode);
00435     if (parentNode) {
00436       if (linkCount++ == NS_STATIC_CAST(PRUint32, aIndex)) {
00437         nsCOMPtr<nsIWeakReference> weakShell;
00438         nsAccessibilityService::GetShellFromNode(parentNode, getter_AddRefs(weakShell));
00439         NS_ENSURE_TRUE(weakShell, NS_ERROR_FAILURE);
00440 
00441         // Check to see if we already have it in the cache.
00442         nsCOMPtr<nsIAccessibilityService>
00443           accService(do_GetService("@mozilla.org/accessibilityService;1"));
00444         NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
00445 
00446         nsCOMPtr<nsIAccessible> cachedAcc;
00447         nsresult rv = accService->GetCachedAccessible(parentNode, weakShell,
00448                                              getter_AddRefs(cachedAcc));
00449         NS_ENSURE_SUCCESS(rv, rv);
00450         *aLink = nsnull;
00451         if (cachedAcc) {
00452           // Retrieved from cache
00453           nsCOMPtr<nsIAccessibleHyperLink> cachedLink(do_QueryInterface(cachedAcc));
00454           if (cachedLink) {
00455             *aLink = cachedLink;
00456             NS_IF_ADDREF(*aLink);
00457           }
00458         }
00459         if (!(*aLink)) {
00460           *aLink = new nsHTMLLinkAccessibleWrap(parentNode, mTextChildren, weakShell, nsnull);
00461           NS_ENSURE_TRUE(*aLink, NS_ERROR_OUT_OF_MEMORY);
00462           NS_ADDREF(*aLink);
00463           nsCOMPtr<nsPIAccessNode> accessNode(do_QueryInterface(*aLink));
00464           accessNode->Init();
00465         }
00466         break;
00467       }
00468     }
00469   }
00470 
00471   return NS_OK;
00472 }
00473 
00474 /* long getLinkIndex (in long charIndex); */
00475 NS_IMETHODIMP nsAccessibleHyperText::GetLinkIndex(PRInt32 aCharIndex, PRInt32 *aLinkIndex)
00476 {
00477   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00478 
00479   *aLinkIndex = -1;
00480   PRInt32 beforeLength_unused;
00481   PRUint32 nodeIndex;
00482   nsIDOMNode* domNode = FindTextNodeByOffset(aCharIndex, beforeLength_unused);
00483   if (GetLinkNode(domNode)
00484       && NS_SUCCEEDED(mTextChildren->IndexOf(0, domNode, &nodeIndex))) {
00485     (*aLinkIndex)++;
00486     for (PRUint32 index = 0; index < nodeIndex; index++) {
00487       nsCOMPtr<nsIDOMNode> childNode(do_QueryElementAt(mTextChildren, index));
00488       if (GetLinkNode(childNode)) {
00489         (*aLinkIndex)++;
00490       }
00491     }
00492   }
00493   return NS_OK;
00494 }
00495 
00496 /* long getSelectedLinkIndex (); */
00497 NS_IMETHODIMP nsAccessibleHyperText::GetSelectedLinkIndex(PRInt32 *aSelectedLinkIndex)
00498 {
00499   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00500 
00501   *aSelectedLinkIndex = -1;
00502 
00503   PRUint32 count;
00504   mTextChildren->GetLength(&count);
00505   if (count <= 0)
00506     return NS_ERROR_FAILURE;
00507 
00508   nsCOMPtr<nsIDOMNode> curNode(do_QueryElementAt(mTextChildren, 0));
00509 
00510   PRUint32 index, linkCount = 0;
00511   for (index = 0; index < count; index++) {
00512     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00513     nsIDOMNode* linkNode = GetLinkNode(domNode);
00514     if (linkNode) {
00515       if (linkNode == nsAccessNode::gLastFocusedNode) {
00516         *aSelectedLinkIndex = linkCount;
00517         return NS_OK;
00518       }
00519       linkCount++;
00520     }
00521   }
00522 
00523   return NS_ERROR_FAILURE;
00524 }
00525 
00526 nsresult nsAccessibleHyperText::GetBounds(nsIWeakReference *aWeakShell, PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
00527 {
00528   NS_ENSURE_TRUE(mTextChildren, NS_ERROR_FAILURE);
00529 
00530   *x = *y = *width = *height = 0;
00531 
00532   nsRect unionRectTwips;
00533   PRUint32 index, count;
00534   mTextChildren->GetLength(&count);
00535   for (index = 0; index < count; index++) {
00536     nsCOMPtr<nsIDOMNode> domNode(do_QueryElementAt(mTextChildren, index));
00537     nsHTMLTextAccessible *accText = new nsHTMLTextAccessible(domNode, aWeakShell, nsnull);
00538     if (!accText)
00539       return NS_ERROR_OUT_OF_MEMORY;
00540 
00541     nsRect frameRect;
00542     accText->GetBounds(&frameRect.x, &frameRect.y, &frameRect.width, &frameRect.height);
00543     unionRectTwips.UnionRect(unionRectTwips, frameRect);
00544     delete accText;
00545   }
00546 
00547   *x      = unionRectTwips.x; 
00548   *y      = unionRectTwips.y;
00549   *width  = unionRectTwips.width;
00550   *height = unionRectTwips.height;
00551 
00552   return NS_OK;
00553 }
00554 
00555 nsIDOMNode* nsAccessibleHyperText::GetLinkNode(nsIDOMNode* aNode)
00556 {
00557   
00558   nsCOMPtr<nsIDOMNode> parentNode;
00559   nsCOMPtr<nsILink> link;
00560   while (aNode && link == nsnull) {
00561     // text node maybe a child (or grandchild, ...) of a link node
00562     aNode->GetParentNode(getter_AddRefs(parentNode));
00563     aNode = parentNode;
00564     link = do_QueryInterface(parentNode);
00565   }
00566   
00567   return parentNode;
00568 }