LCOV - code coverage report
Current view: directory - accessible/src/html - nsHyperTextAccessible.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1159 0 0.0 %
Date: 2012-06-02 Functions: 62 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developers of the Original Code are
      18                 :  * Sun Microsystems and IBM Corporation
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2006
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Ginn Chen (ginn.chen@sun.com)
      24                 :  *   Aaron Leventhal (aleventh@us.ibm.com)
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsHyperTextAccessible.h"
      41                 : 
      42                 : #include "nsAccessibilityService.h"
      43                 : #include "nsAccUtils.h"
      44                 : #include "nsDocAccessible.h"
      45                 : #include "Role.h"
      46                 : #include "States.h"
      47                 : #include "TextAttrs.h"
      48                 : 
      49                 : #include "nsIClipboard.h"
      50                 : #include "nsContentUtils.h"
      51                 : #include "nsFocusManager.h"
      52                 : #include "nsIDOMCharacterData.h"
      53                 : #include "nsIDOMDocument.h"
      54                 : #include "nsIDOMRange.h"
      55                 : #include "nsIDOMXULDocument.h"
      56                 : #include "nsIEditingSession.h"
      57                 : #include "nsIEditor.h"
      58                 : #include "nsIFrame.h"
      59                 : #include "nsFrameSelection.h"
      60                 : #include "nsILineIterator.h"
      61                 : #include "nsIInterfaceRequestorUtils.h"
      62                 : #include "nsIPlaintextEditor.h"
      63                 : #include "nsIScrollableFrame.h"
      64                 : #include "nsISelectionPrivate.h"
      65                 : #include "nsIServiceManager.h"
      66                 : #include "nsTextFragment.h"
      67                 : #include "gfxSkipChars.h"
      68                 : 
      69                 : using namespace mozilla::a11y;
      70                 : 
      71                 : ////////////////////////////////////////////////////////////////////////////////
      72                 : // nsHyperTextAccessible
      73                 : ////////////////////////////////////////////////////////////////////////////////
      74                 : 
      75               0 : nsHyperTextAccessible::
      76                 :   nsHyperTextAccessible(nsIContent* aNode, nsDocAccessible* aDoc) :
      77               0 :   nsAccessibleWrap(aNode, aDoc)
      78                 : {
      79               0 :   mFlags |= eHyperTextAccessible;
      80               0 : }
      81                 : 
      82               0 : NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
      83               0 : NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
      84                 : 
      85               0 : nsresult nsHyperTextAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr)
      86                 : {
      87               0 :   *aInstancePtr = nsnull;
      88                 : 
      89               0 :   if (aIID.Equals(NS_GET_IID(nsHyperTextAccessible))) {
      90               0 :     *aInstancePtr = static_cast<nsHyperTextAccessible*>(this);
      91               0 :     NS_ADDREF_THIS();
      92               0 :     return NS_OK;
      93                 :   }
      94                 : 
      95               0 :   if (mRoleMapEntry &&
      96                 :       (mRoleMapEntry->role == roles::GRAPHIC ||
      97                 :        mRoleMapEntry->role == roles::IMAGE_MAP ||
      98                 :        mRoleMapEntry->role == roles::SLIDER ||
      99                 :        mRoleMapEntry->role == roles::PROGRESSBAR ||
     100                 :        mRoleMapEntry->role == roles::SEPARATOR)) {
     101                 :     // ARIA roles that these interfaces are not appropriate for
     102               0 :     return nsAccessible::QueryInterface(aIID, aInstancePtr);
     103                 :   }
     104                 : 
     105               0 :   if (aIID.Equals(NS_GET_IID(nsIAccessibleText))) {
     106               0 :     *aInstancePtr = static_cast<nsIAccessibleText*>(this);
     107               0 :     NS_ADDREF_THIS();
     108               0 :     return NS_OK;
     109                 :   }
     110                 : 
     111               0 :   if (aIID.Equals(NS_GET_IID(nsIAccessibleHyperText))) {
     112               0 :     *aInstancePtr = static_cast<nsIAccessibleHyperText*>(this);
     113               0 :     NS_ADDREF_THIS();
     114               0 :     return NS_OK;
     115                 :   }
     116                 : 
     117               0 :   if (aIID.Equals(NS_GET_IID(nsIAccessibleEditableText))) {
     118               0 :     *aInstancePtr = static_cast<nsIAccessibleEditableText*>(this);
     119               0 :     NS_ADDREF_THIS();
     120               0 :     return NS_OK;
     121                 :   }
     122                 : 
     123               0 :   return nsAccessible::QueryInterface(aIID, aInstancePtr);
     124                 : }
     125                 : 
     126                 : role
     127               0 : nsHyperTextAccessible::NativeRole()
     128                 : {
     129               0 :   nsIAtom *tag = mContent->Tag();
     130                 : 
     131               0 :   if (tag == nsGkAtoms::form)
     132               0 :     return roles::FORM;
     133                 : 
     134               0 :   if (tag == nsGkAtoms::blockquote || tag == nsGkAtoms::div ||
     135                 :       tag == nsGkAtoms::nav)
     136               0 :     return roles::SECTION;
     137                 : 
     138               0 :   if (tag == nsGkAtoms::h1 || tag == nsGkAtoms::h2 ||
     139                 :       tag == nsGkAtoms::h3 || tag == nsGkAtoms::h4 ||
     140                 :       tag == nsGkAtoms::h5 || tag == nsGkAtoms::h6)
     141               0 :     return roles::HEADING;
     142                 : 
     143               0 :   if (tag == nsGkAtoms::article)
     144               0 :     return roles::DOCUMENT;
     145                 :         
     146                 :   // Deal with html landmark elements
     147               0 :   if (tag == nsGkAtoms::header)
     148               0 :     return roles::HEADER;
     149                 : 
     150               0 :   if (tag == nsGkAtoms::footer)
     151               0 :     return roles::FOOTER;
     152                 : 
     153               0 :   if (tag == nsGkAtoms::aside)
     154               0 :     return roles::NOTE;
     155                 : 
     156                 :   // Treat block frames as paragraphs
     157               0 :   nsIFrame *frame = GetFrame();
     158               0 :   if (frame && frame->GetType() == nsGkAtoms::blockFrame)
     159               0 :     return roles::PARAGRAPH;
     160                 : 
     161               0 :   return roles::TEXT_CONTAINER; // In ATK this works
     162                 : }
     163                 : 
     164                 : PRUint64
     165               0 : nsHyperTextAccessible::NativeState()
     166                 : {
     167               0 :   PRUint64 states = nsAccessibleWrap::NativeState();
     168                 : 
     169               0 :   nsCOMPtr<nsIEditor> editor = GetEditor();
     170               0 :   if (editor) {
     171                 :     PRUint32 flags;
     172               0 :     editor->GetFlags(&flags);
     173               0 :     if (0 == (flags & nsIPlaintextEditor::eEditorReadonlyMask)) {
     174               0 :       states |= states::EDITABLE;
     175                 :     }
     176               0 :   } else if (mContent->Tag() == nsGkAtoms::article) {
     177                 :     // We want <article> to behave like a document in terms of readonly state.
     178               0 :     states |= states::READONLY;
     179                 :   }
     180                 : 
     181               0 :   if (GetChildCount() > 0)
     182               0 :     states |= states::SELECTABLE_TEXT;
     183                 : 
     184               0 :   return states;
     185                 : }
     186                 : 
     187                 : // Substring must be entirely within the same text node
     188               0 : nsIntRect nsHyperTextAccessible::GetBoundsForString(nsIFrame *aFrame, PRUint32 aStartRenderedOffset,
     189                 :                                                     PRUint32 aEndRenderedOffset)
     190                 : {
     191               0 :   nsIntRect screenRect;
     192               0 :   NS_ENSURE_TRUE(aFrame, screenRect);
     193               0 :   if (aFrame->GetType() != nsGkAtoms::textFrame) {
     194                 :     // XXX fallback for non-text frames, happens for bullets right now
     195                 :     // but in the future bullets will have proper text frames
     196               0 :     return aFrame->GetScreenRectExternal();
     197                 :   }
     198                 : 
     199                 :   PRInt32 startContentOffset, endContentOffset;
     200               0 :   nsresult rv = RenderedToContentOffset(aFrame, aStartRenderedOffset, &startContentOffset);
     201               0 :   NS_ENSURE_SUCCESS(rv, screenRect);
     202               0 :   rv = RenderedToContentOffset(aFrame, aEndRenderedOffset, &endContentOffset);
     203               0 :   NS_ENSURE_SUCCESS(rv, screenRect);
     204                 : 
     205                 :   nsIFrame *frame;
     206                 :   PRInt32 startContentOffsetInFrame;
     207                 :   // Get the right frame continuation -- not really a child, but a sibling of
     208                 :   // the primary frame passed in
     209                 :   rv = aFrame->GetChildFrameContainingOffset(startContentOffset, false,
     210               0 :                                              &startContentOffsetInFrame, &frame);
     211               0 :   NS_ENSURE_SUCCESS(rv, screenRect);
     212                 : 
     213               0 :   NS_ENSURE_TRUE(mDoc, screenRect);
     214               0 :   nsIPresShell* shell = mDoc->PresShell();
     215               0 :   NS_ENSURE_TRUE(shell, screenRect);
     216                 : 
     217               0 :   nsPresContext *context = shell->GetPresContext();
     218                 : 
     219               0 :   while (frame && startContentOffset < endContentOffset) {
     220                 :     // Start with this frame's screen rect, which we will 
     221                 :     // shrink based on the substring we care about within it.
     222                 :     // We will then add that frame to the total screenRect we
     223                 :     // are returning.
     224               0 :     nsIntRect frameScreenRect = frame->GetScreenRectExternal();
     225                 : 
     226                 :     // Get the length of the substring in this frame that we want the bounds for
     227                 :     PRInt32 startFrameTextOffset, endFrameTextOffset;
     228               0 :     frame->GetOffsets(startFrameTextOffset, endFrameTextOffset);
     229               0 :     PRInt32 frameTotalTextLength = endFrameTextOffset - startFrameTextOffset;
     230               0 :     PRInt32 seekLength = endContentOffset - startContentOffset;
     231               0 :     PRInt32 frameSubStringLength = NS_MIN(frameTotalTextLength - startContentOffsetInFrame, seekLength);
     232                 : 
     233                 :     // Add the point where the string starts to the frameScreenRect
     234               0 :     nsPoint frameTextStartPoint;
     235               0 :     rv = frame->GetPointFromOffset(startContentOffset, &frameTextStartPoint);
     236               0 :     NS_ENSURE_SUCCESS(rv, nsIntRect());
     237               0 :     frameScreenRect.x += context->AppUnitsToDevPixels(frameTextStartPoint.x);
     238                 : 
     239                 :     // Use the point for the end offset to calculate the width
     240               0 :     nsPoint frameTextEndPoint;
     241               0 :     rv = frame->GetPointFromOffset(startContentOffset + frameSubStringLength, &frameTextEndPoint);
     242               0 :     NS_ENSURE_SUCCESS(rv, nsIntRect());
     243               0 :     frameScreenRect.width = context->AppUnitsToDevPixels(frameTextEndPoint.x - frameTextStartPoint.x);
     244                 : 
     245               0 :     screenRect.UnionRect(frameScreenRect, screenRect);
     246                 : 
     247                 :     // Get ready to loop back for next frame continuation
     248               0 :     startContentOffset += frameSubStringLength;
     249               0 :     startContentOffsetInFrame = 0;
     250               0 :     frame = frame->GetNextContinuation();
     251                 :   }
     252                 : 
     253               0 :   return screenRect;
     254                 : }
     255                 : 
     256                 : /*
     257                 :  * Gets the specified text.
     258                 :  */
     259                 : nsIFrame*
     260               0 : nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset,
     261                 :                                      nsAString *aText, nsIFrame **aEndFrame,
     262                 :                                      nsIntRect *aBoundsRect,
     263                 :                                      nsAccessible **aStartAcc,
     264                 :                                      nsAccessible **aEndAcc)
     265                 : {
     266               0 :   if (aStartOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT) {
     267               0 :     aStartOffset = CharacterCount();
     268                 :   }
     269               0 :   if (aStartOffset == nsIAccessibleText::TEXT_OFFSET_CARET) {
     270               0 :     GetCaretOffset(&aStartOffset);
     271                 :   }
     272               0 :   if (aEndOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT) {
     273               0 :     aEndOffset = CharacterCount();
     274                 :   }
     275               0 :   if (aEndOffset == nsIAccessibleText::TEXT_OFFSET_CARET) {
     276               0 :     GetCaretOffset(&aEndOffset);
     277                 :   }
     278                 : 
     279               0 :   PRInt32 startOffset = aStartOffset;
     280               0 :   PRInt32 endOffset = aEndOffset;
     281                 :   // XXX this prevents text interface usage on <input type="password">
     282               0 :   bool isPassword = (Role() == roles::PASSWORD_TEXT);
     283                 : 
     284                 :   // Clear out parameters and set up loop
     285               0 :   if (aText) {
     286               0 :     aText->Truncate();
     287                 :   }
     288               0 :   if (endOffset < 0) {
     289               0 :     const PRInt32 kMaxTextLength = 32767;
     290               0 :     endOffset = kMaxTextLength; // Max end offset
     291                 :   }
     292               0 :   else if (startOffset > endOffset) {
     293               0 :     return nsnull;
     294                 :   }
     295                 : 
     296               0 :   nsIFrame *startFrame = nsnull;
     297               0 :   if (aEndFrame) {
     298               0 :     *aEndFrame = nsnull;
     299                 :   }
     300               0 :   if (aBoundsRect) {
     301               0 :     aBoundsRect->SetEmpty();
     302                 :   }
     303               0 :   if (aStartAcc)
     304               0 :     *aStartAcc = nsnull;
     305               0 :   if (aEndAcc)
     306               0 :     *aEndAcc = nsnull;
     307                 : 
     308               0 :   nsIntRect unionRect;
     309               0 :   nsAccessible *lastAccessible = nsnull;
     310                 : 
     311               0 :   gfxSkipChars skipChars;
     312               0 :   gfxSkipCharsIterator iter;
     313                 : 
     314                 :   // Loop through children and collect valid offsets, text and bounds
     315                 :   // depending on what we need for out parameters.
     316               0 :   PRInt32 childCount = GetChildCount();
     317               0 :   for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
     318               0 :     nsAccessible *childAcc = mChildren[childIdx];
     319               0 :     lastAccessible = childAcc;
     320                 : 
     321               0 :     nsIFrame *frame = childAcc->GetFrame();
     322               0 :     if (!frame) {
     323               0 :       continue;
     324                 :     }
     325               0 :     nsIFrame *primaryFrame = frame;
     326               0 :     if (nsAccUtils::IsText(childAcc)) {
     327                 :       // We only need info up to rendered offset -- that is what we're
     328                 :       // converting to content offset
     329               0 :       PRInt32 substringEndOffset = -1;
     330               0 :       PRUint32 ourRenderedStart = 0;
     331               0 :       PRInt32 ourContentStart = 0;
     332               0 :       if (frame->GetType() == nsGkAtoms::textFrame) {
     333               0 :         nsresult rv = frame->GetRenderedText(nsnull, &skipChars, &iter);
     334               0 :         if (NS_SUCCEEDED(rv)) {
     335               0 :           ourRenderedStart = iter.GetSkippedOffset();
     336               0 :           ourContentStart = iter.GetOriginalOffset();
     337                 :           substringEndOffset =
     338               0 :             iter.ConvertOriginalToSkipped(skipChars.GetOriginalCharCount() +
     339               0 :                                           ourContentStart) - ourRenderedStart;
     340                 :         }
     341                 :       }
     342               0 :       if (substringEndOffset < 0) {
     343                 :         // XXX for non-textframe text like list bullets,
     344                 :         // should go away after list bullet rewrite
     345               0 :         substringEndOffset = nsAccUtils::TextLength(childAcc);
     346                 :       }
     347               0 :       if (startOffset < substringEndOffset) {
     348                 :         // Our start is within this substring
     349               0 :         if (startOffset > 0 || endOffset < substringEndOffset) {
     350                 :           // We don't want the whole string for this accessible
     351                 :           // Get out the continuing text frame with this offset
     352                 :           PRInt32 outStartLineUnused;
     353                 :           PRInt32 contentOffset;
     354               0 :           if (frame->GetType() == nsGkAtoms::textFrame) {
     355               0 :             contentOffset = iter.ConvertSkippedToOriginal(startOffset) +
     356               0 :                             ourRenderedStart - ourContentStart;
     357                 :           }
     358                 :           else {
     359               0 :             contentOffset = startOffset;
     360                 :           }
     361                 :           frame->GetChildFrameContainingOffset(contentOffset, true,
     362               0 :                                                &outStartLineUnused, &frame);
     363               0 :           if (aEndFrame) {
     364               0 :             *aEndFrame = frame; // We ended in the current frame
     365               0 :             if (aEndAcc)
     366               0 :               NS_ADDREF(*aEndAcc = childAcc);
     367                 :           }
     368               0 :           if (substringEndOffset > endOffset) {
     369                 :             // Need to stop before the end of the available text
     370               0 :             substringEndOffset = endOffset;
     371                 :           }
     372               0 :           aEndOffset = endOffset;
     373                 :         }
     374               0 :         if (aText) {
     375               0 :           if (isPassword) {
     376               0 :             for (PRInt32 count = startOffset; count < substringEndOffset; count ++)
     377               0 :               *aText += '*'; // Show *'s only for password text
     378                 :           }
     379                 :           else {
     380                 :             childAcc->AppendTextTo(*aText, startOffset,
     381               0 :                                    substringEndOffset - startOffset);
     382                 :           }
     383                 :         }
     384               0 :         if (aBoundsRect) {    // Caller wants the bounds of the text
     385                 :           aBoundsRect->UnionRect(*aBoundsRect,
     386                 :                                  GetBoundsForString(primaryFrame, startOffset,
     387               0 :                                                     substringEndOffset));
     388                 :         }
     389               0 :         if (!startFrame) {
     390               0 :           startFrame = frame;
     391               0 :           aStartOffset = startOffset;
     392               0 :           if (aStartAcc)
     393               0 :             NS_ADDREF(*aStartAcc = childAcc);
     394                 :         }
     395                 :         // We already started copying in this accessible's string,
     396                 :         // for the next accessible we'll start at offset 0
     397               0 :         startOffset = 0;
     398                 :       }
     399                 :       else {
     400                 :         // We have not found the start position yet, get the new startOffset
     401                 :         // that is relative to next accessible
     402               0 :         startOffset -= substringEndOffset;
     403                 :       }
     404                 :       // The endOffset needs to be relative to the new startOffset
     405               0 :       endOffset -= substringEndOffset;
     406                 :     }
     407                 :     else {
     408                 :       // Embedded object, append marker
     409                 :       // XXX Append \n for <br>'s
     410               0 :       if (startOffset >= 1) {
     411               0 :         -- startOffset;
     412                 :       }
     413                 :       else {
     414               0 :         if (endOffset > 0) {
     415               0 :           if (aText) {
     416                 :             // XXX: should use nsIAccessible::AppendTextTo.
     417               0 :             if (frame->GetType() == nsGkAtoms::brFrame) {
     418               0 :               *aText += kForcedNewLineChar;
     419               0 :             } else if (nsAccUtils::MustPrune(this)) {
     420               0 :               *aText += kImaginaryEmbeddedObjectChar;
     421                 :               // Expose imaginary embedded object character if the accessible
     422                 :               // hans't children.
     423                 :             } else {
     424               0 :               *aText += kEmbeddedObjectChar;
     425                 :             }
     426                 :           }
     427               0 :           if (aBoundsRect) {
     428                 :             aBoundsRect->UnionRect(*aBoundsRect,
     429               0 :                                    frame->GetScreenRectExternal());
     430                 :           }
     431                 :         }
     432               0 :         if (!startFrame) {
     433               0 :           startFrame = frame;
     434               0 :           aStartOffset = 0;
     435               0 :           if (aStartAcc)
     436               0 :             NS_ADDREF(*aStartAcc = childAcc);
     437                 :         }
     438                 :       }
     439               0 :       -- endOffset;
     440                 :     }
     441               0 :     if (endOffset <= 0 && startFrame) {
     442               0 :       break; // If we don't have startFrame yet, get that in next loop iteration
     443                 :     }
     444                 :   }
     445                 : 
     446               0 :   if (aStartAcc && !*aStartAcc) {
     447               0 :     NS_IF_ADDREF(*aStartAcc = lastAccessible);
     448                 :   }
     449               0 :   if (aEndFrame && !*aEndFrame) {
     450               0 :     *aEndFrame = startFrame;
     451               0 :     if (aStartAcc && aEndAcc)
     452               0 :       NS_IF_ADDREF(*aEndAcc = *aStartAcc);
     453                 :   }
     454                 : 
     455               0 :   return startFrame;
     456                 : }
     457                 : 
     458                 : NS_IMETHODIMP
     459               0 : nsHyperTextAccessible::GetText(PRInt32 aStartOffset, PRInt32 aEndOffset,
     460                 :                                nsAString &aText)
     461                 : {
     462               0 :   aText.Truncate();
     463                 : 
     464               0 :   if (IsDefunct())
     465               0 :     return NS_ERROR_FAILURE;
     466                 : 
     467               0 :   PRInt32 startOffset = ConvertMagicOffset(aStartOffset);
     468               0 :   PRInt32 startChildIdx = GetChildIndexAtOffset(startOffset);
     469               0 :   if (startChildIdx == -1)
     470               0 :     return NS_ERROR_INVALID_ARG;
     471                 : 
     472               0 :   PRInt32 endOffset = ConvertMagicOffset(aEndOffset);
     473               0 :   PRInt32 endChildIdx = GetChildIndexAtOffset(endOffset);
     474               0 :   if (endChildIdx == -1)
     475               0 :     return NS_ERROR_INVALID_ARG;
     476                 : 
     477               0 :   if (startChildIdx == endChildIdx) {
     478               0 :     PRInt32 childOffset =  GetChildOffset(startChildIdx);
     479               0 :     NS_ENSURE_STATE(childOffset != -1);
     480                 : 
     481               0 :     nsAccessible* child = GetChildAt(startChildIdx);
     482                 :     child->AppendTextTo(aText, startOffset - childOffset,
     483               0 :                         endOffset - startOffset);
     484                 : 
     485               0 :     return NS_OK;
     486                 :   }
     487                 : 
     488               0 :   PRInt32 startChildOffset =  GetChildOffset(startChildIdx);
     489               0 :   NS_ENSURE_STATE(startChildOffset != -1);
     490                 : 
     491               0 :   nsAccessible* startChild = GetChildAt(startChildIdx);
     492               0 :   startChild->AppendTextTo(aText, startOffset - startChildOffset);
     493                 : 
     494               0 :   for (PRInt32 childIdx = startChildIdx + 1; childIdx < endChildIdx; childIdx++) {
     495               0 :     nsAccessible* child = GetChildAt(childIdx);
     496               0 :     child->AppendTextTo(aText);
     497                 :   }
     498                 : 
     499               0 :   PRInt32 endChildOffset =  GetChildOffset(endChildIdx);
     500               0 :   NS_ENSURE_STATE(endChildOffset != -1);
     501                 : 
     502               0 :   nsAccessible* endChild = GetChildAt(endChildIdx);
     503               0 :   endChild->AppendTextTo(aText, 0, endOffset - endChildOffset);
     504                 : 
     505               0 :   return NS_OK;
     506                 : }
     507                 : 
     508                 : /*
     509                 :  * Gets the character count.
     510                 :  */
     511               0 : NS_IMETHODIMP nsHyperTextAccessible::GetCharacterCount(PRInt32 *aCharacterCount)
     512                 : {
     513               0 :   NS_ENSURE_ARG_POINTER(aCharacterCount);
     514               0 :   *aCharacterCount = 0;
     515                 : 
     516               0 :   if (IsDefunct())
     517               0 :     return NS_ERROR_FAILURE;
     518                 : 
     519               0 :   *aCharacterCount = CharacterCount();
     520               0 :   return NS_OK;
     521                 : }
     522                 : 
     523                 : /*
     524                 :  * Gets the specified character.
     525                 :  */
     526               0 : NS_IMETHODIMP nsHyperTextAccessible::GetCharacterAtOffset(PRInt32 aOffset, PRUnichar *aCharacter)
     527                 : {
     528               0 :   NS_ENSURE_ARG_POINTER(aCharacter);
     529               0 :   *aCharacter = nsnull;
     530                 : 
     531               0 :   if (IsDefunct())
     532               0 :     return NS_ERROR_FAILURE;
     533                 : 
     534               0 :   nsAutoString character;
     535               0 :   if (GetCharAt(aOffset, eGetAt, character)) {
     536               0 :     *aCharacter = character.First();
     537               0 :     return NS_OK;
     538                 :   }
     539                 : 
     540               0 :   return NS_ERROR_INVALID_ARG;
     541                 : }
     542                 : 
     543                 : nsAccessible*
     544               0 : nsHyperTextAccessible::DOMPointToHypertextOffset(nsINode *aNode,
     545                 :                                                  PRInt32 aNodeOffset,
     546                 :                                                  PRInt32 *aHyperTextOffset,
     547                 :                                                  bool aIsEndOffset)
     548                 : {
     549               0 :   if (!aHyperTextOffset)
     550               0 :     return nsnull;
     551               0 :   *aHyperTextOffset = 0;
     552                 : 
     553               0 :   if (!aNode)
     554               0 :     return nsnull;
     555                 : 
     556               0 :   PRUint32 addTextOffset = 0;
     557               0 :   nsINode* findNode = nsnull;
     558                 : 
     559               0 :   if (aNodeOffset == -1) {
     560               0 :     findNode = aNode;
     561                 : 
     562               0 :   } else if (aNode->IsNodeOfType(nsINode::eTEXT)) {
     563                 :     // For text nodes, aNodeOffset comes in as a character offset
     564                 :     // Text offset will be added at the end, if we find the offset in this hypertext
     565                 :     // We want the "skipped" offset into the text (rendered text without the extra whitespace)
     566               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
     567               0 :     NS_ASSERTION(content, "No nsIContent for dom node");
     568               0 :     nsIFrame *frame = content->GetPrimaryFrame();
     569               0 :     NS_ENSURE_TRUE(frame, nsnull);
     570               0 :     nsresult rv = ContentToRenderedOffset(frame, aNodeOffset, &addTextOffset);
     571               0 :     NS_ENSURE_SUCCESS(rv, nsnull);
     572                 :     // Get the child node and 
     573               0 :     findNode = aNode;
     574                 : 
     575                 :   } else {
     576                 :     // findNode could be null if aNodeOffset == # of child nodes, which means
     577                 :     // one of two things:
     578                 :     // 1) we're at the end of the children, keep findNode = null, so that we get
     579                 :     //    the last possible offset
     580                 :     // 2) there are no children and the passed-in node is mContent, which means
     581                 :     //    we're an aempty nsIAccessibleText
     582                 :     // 3) there are no children, and the passed-in node is not mContent -- use
     583                 :     //    parentContent for the node to find
     584                 : 
     585               0 :     findNode = aNode->GetChildAt(aNodeOffset);
     586               0 :     if (!findNode && !aNodeOffset) {
     587               0 :       if (aNode == GetNode()) {
     588                 :         // There are no children, which means this is an empty nsIAccessibleText, in which
     589                 :         // case we can only be at hypertext offset 0
     590               0 :         *aHyperTextOffset = 0;
     591               0 :         return nsnull;
     592                 :       }
     593               0 :       findNode = aNode; // Case #2: there are no children
     594                 :     }
     595                 :   }
     596                 : 
     597                 :   // Get accessible for this findNode, or if that node isn't accessible, use the
     598                 :   // accessible for the next DOM node which has one (based on forward depth first search)
     599               0 :   nsAccessible *descendantAcc = nsnull;
     600               0 :   if (findNode) {
     601               0 :     nsCOMPtr<nsIContent> findContent(do_QueryInterface(findNode));
     602               0 :     if (findContent && findContent->IsHTML() &&
     603               0 :         findContent->NodeInfo()->Equals(nsGkAtoms::br) &&
     604               0 :         findContent->AttrValueIs(kNameSpaceID_None,
     605                 :                                  nsGkAtoms::mozeditorbogusnode,
     606                 :                                  nsGkAtoms::_true,
     607               0 :                                  eIgnoreCase)) {
     608                 :       // This <br> is the hacky "bogus node" used when there is no text in a control
     609               0 :       *aHyperTextOffset = 0;
     610               0 :       return nsnull;
     611                 :     }
     612               0 :     descendantAcc = GetFirstAvailableAccessible(findNode);
     613                 :   }
     614                 : 
     615                 :   // From the descendant, go up and get the immediate child of this hypertext
     616               0 :   nsAccessible* childAccAtOffset = nsnull;
     617               0 :   while (descendantAcc) {
     618               0 :     nsAccessible* parentAcc = descendantAcc->Parent();
     619               0 :     if (parentAcc == this) {
     620               0 :       childAccAtOffset = descendantAcc;
     621               0 :       break;
     622                 :     }
     623                 : 
     624                 :     // This offset no longer applies because the passed-in text object is not a child
     625                 :     // of the hypertext. This happens when there are nested hypertexts, e.g.
     626                 :     // <div>abc<h1>def</h1>ghi</div>
     627                 :     // If the passed-in DOM point was not on a direct child of the hypertext, we will
     628                 :     // return the offset for that entire hypertext
     629               0 :     if (aIsEndOffset) {
     630                 :       // Not inclusive, the indicated char comes at index before this offset
     631                 :       // If the end offset is after the first character of the passed in object, use 1 for
     632                 :     // addTextOffset, to put us after the embedded object char. We'll only treat the offset as
     633                 :     // before the embedded object char if we end at the very beginning of the child.
     634               0 :     addTextOffset = addTextOffset > 0;
     635                 :     }
     636                 :     else {
     637                 :       // Start offset, inclusive
     638                 :       // Make sure the offset lands on the embedded object character in order to indicate
     639                 :       // the true inner offset is inside the subtree for that link
     640                 :       addTextOffset =
     641               0 :         (nsAccUtils::TextLength(descendantAcc) == addTextOffset) ? 1 : 0;
     642                 :     }
     643                 : 
     644               0 :     descendantAcc = parentAcc;
     645                 :   }
     646                 : 
     647                 :   // Loop through, adding offsets until we reach childAccessible
     648                 :   // If childAccessible is null we will end up adding up the entire length of
     649                 :   // the hypertext, which is good -- it just means our offset node
     650                 :   // came after the last accessible child's node
     651               0 :   PRInt32 childCount = GetChildCount();
     652                 : 
     653               0 :   PRInt32 childIdx = 0;
     654               0 :   nsAccessible *childAcc = nsnull;
     655               0 :   for (; childIdx < childCount; childIdx++) {
     656               0 :     childAcc = mChildren[childIdx];
     657               0 :     if (childAcc == childAccAtOffset)
     658               0 :       break;
     659                 : 
     660               0 :     *aHyperTextOffset += nsAccUtils::TextLength(childAcc);
     661                 :   }
     662                 : 
     663               0 :   if (childIdx < childCount) {
     664               0 :     *aHyperTextOffset += addTextOffset;
     665               0 :     NS_ASSERTION(childAcc == childAccAtOffset,
     666                 :                  "These should be equal whenever we exit loop and childAcc != nsnull");
     667                 : 
     668               0 :     if (childIdx < childCount - 1 ||
     669               0 :         addTextOffset < nsAccUtils::TextLength(childAccAtOffset)) {
     670                 :       // If not at end of last text node, we will return the accessible we were in
     671               0 :       return childAccAtOffset;
     672                 :     }
     673                 :   }
     674                 : 
     675               0 :   return nsnull;
     676                 : }
     677                 : 
     678                 : nsresult
     679               0 : nsHyperTextAccessible::HypertextOffsetToDOMPoint(PRInt32 aHTOffset,
     680                 :                                                  nsIDOMNode **aNode,
     681                 :                                                  PRInt32 *aOffset)
     682                 : {
     683               0 :   nsCOMPtr<nsIDOMNode> endNode;
     684                 :   PRInt32 endOffset;
     685                 : 
     686                 :   return HypertextOffsetsToDOMRange(aHTOffset, aHTOffset, aNode, aOffset,
     687               0 :                                     getter_AddRefs(endNode), &endOffset);
     688                 : }
     689                 : 
     690                 : nsresult
     691               0 : nsHyperTextAccessible::HypertextOffsetsToDOMRange(PRInt32 aStartHTOffset,
     692                 :                                                   PRInt32 aEndHTOffset,
     693                 :                                                   nsIDOMNode **aStartNode,
     694                 :                                                   PRInt32 *aStartOffset,
     695                 :                                                   nsIDOMNode **aEndNode,
     696                 :                                                   PRInt32 *aEndOffset)
     697                 : {
     698               0 :   NS_ENSURE_ARG_POINTER(aStartNode);
     699               0 :   *aStartNode = nsnull;
     700                 : 
     701               0 :   NS_ENSURE_ARG_POINTER(aStartOffset);
     702               0 :   *aStartOffset = -1;
     703                 : 
     704               0 :   NS_ENSURE_ARG_POINTER(aEndNode);
     705               0 :   *aEndNode = nsnull;
     706                 : 
     707               0 :   NS_ENSURE_ARG_POINTER(aEndOffset);
     708               0 :   *aEndOffset = -1;
     709                 : 
     710                 :   // If the given offsets are 0 and associated editor is empty then return
     711                 :   // collapsed range with editor root element as range container.
     712               0 :   if (aStartHTOffset == 0 && aEndHTOffset == 0) {
     713               0 :     nsCOMPtr<nsIEditor> editor = GetEditor();
     714               0 :     if (editor) {
     715               0 :       bool isEmpty = false;
     716               0 :       editor->GetDocumentIsEmpty(&isEmpty);
     717               0 :       if (isEmpty) {
     718               0 :         nsCOMPtr<nsIDOMElement> editorRootElm;
     719               0 :         editor->GetRootElement(getter_AddRefs(editorRootElm));
     720                 : 
     721               0 :         nsCOMPtr<nsIDOMNode> editorRoot(do_QueryInterface(editorRootElm));
     722               0 :         if (editorRoot) {
     723               0 :           *aStartOffset = *aEndOffset = 0;
     724               0 :           NS_ADDREF(*aStartNode = editorRoot);
     725               0 :           NS_ADDREF(*aEndNode = editorRoot);
     726                 : 
     727               0 :           return NS_OK;
     728                 :         }
     729                 :       }
     730                 :     }
     731                 :   }
     732                 : 
     733               0 :   nsRefPtr<nsAccessible> startAcc, endAcc;
     734               0 :   PRInt32 startOffset = aStartHTOffset, endOffset = aEndHTOffset;
     735               0 :   nsIFrame *startFrame = nsnull, *endFrame = nsnull;
     736                 : 
     737                 :   startFrame = GetPosAndText(startOffset, endOffset, nsnull, &endFrame, nsnull,
     738               0 :                              getter_AddRefs(startAcc), getter_AddRefs(endAcc));
     739               0 :   if (!startAcc || !endAcc)
     740               0 :     return NS_ERROR_FAILURE;
     741                 : 
     742               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
     743                 :   nsresult rv = GetDOMPointByFrameOffset(startFrame, startOffset, startAcc,
     744               0 :                                          getter_AddRefs(startNode),
     745               0 :                                          &startOffset);
     746               0 :   NS_ENSURE_SUCCESS(rv, rv);
     747                 : 
     748               0 :   if (aStartHTOffset != aEndHTOffset) {
     749                 :     rv = GetDOMPointByFrameOffset(endFrame, endOffset, endAcc,
     750               0 :                                   getter_AddRefs(endNode), &endOffset);
     751               0 :     NS_ENSURE_SUCCESS(rv, rv);
     752                 :   } else {
     753               0 :     endNode = startNode;
     754               0 :     endOffset = startOffset;
     755                 :   }
     756                 : 
     757               0 :   NS_ADDREF(*aStartNode = startNode);
     758               0 :   *aStartOffset = startOffset;
     759                 : 
     760               0 :   NS_ADDREF(*aEndNode = endNode);
     761               0 :   *aEndOffset = endOffset;
     762                 : 
     763               0 :   return NS_OK;
     764                 : }
     765                 : 
     766                 : PRInt32
     767               0 : nsHyperTextAccessible::GetRelativeOffset(nsIPresShell *aPresShell,
     768                 :                                          nsIFrame *aFromFrame,
     769                 :                                          PRInt32 aFromOffset,
     770                 :                                          nsAccessible *aFromAccessible,
     771                 :                                          nsSelectionAmount aAmount,
     772                 :                                          nsDirection aDirection,
     773                 :                                          bool aNeedsStart)
     774                 : {
     775               0 :   const bool kIsJumpLinesOk = true;          // okay to jump lines
     776               0 :   const bool kIsScrollViewAStop = false;     // do not stop at scroll views
     777               0 :   const bool kIsKeyboardSelect = true;       // is keyboard selection
     778               0 :   const bool kIsVisualBidi = false;          // use visual order for bidi text
     779                 : 
     780               0 :   EWordMovementType wordMovementType = aNeedsStart ? eStartWord : eEndWord;
     781               0 :   if (aAmount == eSelectLine) {
     782               0 :     aAmount = (aDirection == eDirNext) ? eSelectEndLine : eSelectBeginLine;
     783                 :   }
     784                 : 
     785                 :   // Ask layout for the new node and offset, after moving the appropriate amount
     786               0 :   nsPeekOffsetStruct pos;
     787                 : 
     788                 :   nsresult rv;
     789               0 :   PRInt32 contentOffset = aFromOffset;
     790               0 :   if (nsAccUtils::IsText(aFromAccessible)) {
     791               0 :     nsIFrame *frame = aFromAccessible->GetFrame();
     792               0 :     NS_ENSURE_TRUE(frame, -1);
     793                 : 
     794               0 :     if (frame->GetType() == nsGkAtoms::textFrame) {
     795               0 :       rv = RenderedToContentOffset(frame, aFromOffset, &contentOffset);
     796               0 :       NS_ENSURE_SUCCESS(rv, -1);
     797                 :     }
     798                 :   }
     799                 : 
     800                 :   pos.SetData(aAmount, aDirection, contentOffset,
     801                 :               0, kIsJumpLinesOk, kIsScrollViewAStop, kIsKeyboardSelect, kIsVisualBidi,
     802               0 :               wordMovementType);
     803               0 :   rv = aFromFrame->PeekOffset(&pos);
     804               0 :   if (NS_FAILED(rv)) {
     805               0 :     if (aDirection == eDirPrevious) {
     806                 :       // Use passed-in frame as starting point in failure case for now,
     807                 :       // this is a hack to deal with starting on a list bullet frame,
     808                 :       // which fails in PeekOffset() because the line iterator doesn't see it.
     809                 :       // XXX Need to look at our overall handling of list bullets, which are an odd case
     810               0 :       pos.mResultContent = aFromFrame->GetContent();
     811                 :       PRInt32 endOffsetUnused;
     812               0 :       aFromFrame->GetOffsets(pos.mContentOffset, endOffsetUnused);
     813                 :     }
     814                 :     else {
     815               0 :       return -1;
     816                 :     }
     817                 :   }
     818                 : 
     819                 :   // Turn the resulting node and offset into a hyperTextOffset
     820                 :   PRInt32 hyperTextOffset;
     821               0 :   if (!pos.mResultContent)
     822               0 :     return -1;
     823                 : 
     824                 :   // If finalAccessible is nsnull, then DOMPointToHypertextOffset() searched
     825                 :   // through the hypertext children without finding the node/offset position.
     826                 :   nsAccessible *finalAccessible =
     827                 :     DOMPointToHypertextOffset(pos.mResultContent, pos.mContentOffset,
     828               0 :                               &hyperTextOffset, aDirection == eDirNext);
     829                 : 
     830               0 :   if (!finalAccessible && aDirection == eDirPrevious) {
     831                 :     // If we reached the end during search, this means we didn't find the DOM point
     832                 :     // and we're actually at the start of the paragraph
     833               0 :     hyperTextOffset = 0;
     834                 :   }  
     835               0 :   else if (aAmount == eSelectBeginLine) {
     836               0 :     nsAccessible *firstChild = mChildren.SafeElementAt(0, nsnull);
     837                 :     // For line selection with needsStart, set start of line exactly to line break
     838               0 :     if (pos.mContentOffset == 0 && firstChild &&
     839               0 :         firstChild->Role() == roles::STATICTEXT &&
     840               0 :         static_cast<PRInt32>(nsAccUtils::TextLength(firstChild)) == hyperTextOffset) {
     841                 :       // XXX Bullet hack -- we should remove this once list bullets use anonymous content
     842               0 :       hyperTextOffset = 0;
     843                 :     }
     844               0 :     if (!aNeedsStart && hyperTextOffset > 0) {
     845               0 :       -- hyperTextOffset;
     846                 :     }
     847                 :   }
     848               0 :   else if (aAmount == eSelectEndLine && finalAccessible) { 
     849                 :     // If not at very end of hypertext, we may need change the end of line offset by 1, 
     850                 :     // to make sure we are in the right place relative to the line ending
     851               0 :     if (finalAccessible->Role() == roles::WHITESPACE) {  // Landed on <br> hard line break
     852                 :       // if aNeedsStart, set end of line exactly 1 character past line break
     853                 :       // XXX It would be cleaner if we did not have to have the hard line break check,
     854                 :       // and just got the correct results from PeekOffset() for the <br> case -- the returned offset should
     855                 :       // come after the new line, as it does in other cases.
     856               0 :       ++ hyperTextOffset;  // Get past hard line break
     857                 :     }
     858                 :     // We are now 1 character past the line break
     859               0 :     if (!aNeedsStart) {
     860               0 :       -- hyperTextOffset;
     861                 :     }
     862                 :   }
     863                 : 
     864               0 :   return hyperTextOffset;
     865                 : }
     866                 : 
     867                 : /*
     868                 : Gets the specified text relative to aBoundaryType, which means:
     869                 : BOUNDARY_CHAR             The character before/at/after the offset is returned.
     870                 : BOUNDARY_WORD_START       From the word start before/at/after the offset to the next word start.
     871                 : BOUNDARY_WORD_END         From the word end before/at/after the offset to the next work end.
     872                 : BOUNDARY_LINE_START       From the line start before/at/after the offset to the next line start.
     873                 : BOUNDARY_LINE_END         From the line end before/at/after the offset to the next line start.
     874                 : */
     875                 : 
     876               0 : nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTextBoundary aBoundaryType,
     877                 :                                               PRInt32 aOffset, PRInt32 *aStartOffset, PRInt32 *aEndOffset,
     878                 :                                               nsAString &aText)
     879                 : {
     880               0 :   aText.Truncate();
     881                 : 
     882               0 :   NS_ENSURE_ARG_POINTER(aStartOffset);
     883               0 :   NS_ENSURE_ARG_POINTER(aEndOffset);
     884               0 :   *aStartOffset = *aEndOffset = 0;
     885                 : 
     886               0 :   if (!mDoc)
     887               0 :     return NS_ERROR_FAILURE;
     888                 : 
     889               0 :   nsIPresShell* presShell = mDoc->PresShell();
     890               0 :   if (!presShell) {
     891               0 :     return NS_ERROR_FAILURE;
     892                 :   }
     893                 : 
     894               0 :   if (aOffset == nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT) {
     895               0 :     aOffset = CharacterCount();
     896                 :   }
     897               0 :   if (aOffset == nsIAccessibleText::TEXT_OFFSET_CARET) {
     898               0 :     GetCaretOffset(&aOffset);
     899               0 :     if (aOffset > 0 && (aBoundaryType == BOUNDARY_LINE_START ||
     900                 :                         aBoundaryType == BOUNDARY_LINE_END)) {
     901                 :       // It is the same character offset when the caret is visually at the very end of a line
     902                 :       // or the start of a new line. Getting text at the line should provide the line with the visual caret,
     903                 :       // otherwise screen readers will announce the wrong line as the user presses up or down arrow and land
     904                 :       // at the end of a line.
     905               0 :       nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
     906               0 :       if (frameSelection &&
     907               0 :           frameSelection->GetHint() == nsFrameSelection::HINTLEFT) {
     908               0 :         -- aOffset;  // We are at the start of a line
     909                 :       }
     910                 :     }
     911                 :   }
     912               0 :   else if (aOffset < 0) {
     913               0 :     return NS_ERROR_FAILURE;
     914                 :   }
     915                 : 
     916                 :   nsSelectionAmount amount;
     917               0 :   bool needsStart = false;
     918               0 :   switch (aBoundaryType) {
     919                 :     case BOUNDARY_CHAR:
     920               0 :       amount = eSelectCluster;
     921               0 :       if (aType == eGetAt)
     922               0 :         aType = eGetAfter; // Avoid returning 2 characters
     923               0 :       break;
     924                 : 
     925                 :     case BOUNDARY_WORD_START:
     926               0 :       needsStart = true;
     927               0 :       amount = eSelectWord;
     928               0 :       break;
     929                 : 
     930                 :     case BOUNDARY_WORD_END:
     931               0 :       amount = eSelectWord;
     932               0 :       break;
     933                 : 
     934                 :     case BOUNDARY_LINE_START:
     935                 :       // Newlines are considered at the end of a line. Since getting
     936                 :       // the BOUNDARY_LINE_START gets the text from the line-start to the next
     937                 :       // line-start, the newline is included at the end of the string.
     938               0 :       needsStart = true;
     939               0 :       amount = eSelectLine;
     940               0 :       break;
     941                 : 
     942                 :     case BOUNDARY_LINE_END:
     943                 :       // Newlines are considered at the end of a line. Since getting
     944                 :       // the BOUNDARY_END_START gets the text from the line-end to the next
     945                 :       //line-end, the newline is included at the beginning of the string.
     946               0 :       amount = eSelectLine;
     947               0 :       break;
     948                 : 
     949                 :     case BOUNDARY_ATTRIBUTE_RANGE:
     950                 :     {
     951                 :       nsresult rv = GetTextAttributes(false, aOffset,
     952               0 :                                       aStartOffset, aEndOffset, nsnull);
     953               0 :       NS_ENSURE_SUCCESS(rv, rv);
     954                 :       
     955               0 :       return GetText(*aStartOffset, *aEndOffset, aText);
     956                 :     }
     957                 : 
     958                 :     default:  // Note, sentence support is deprecated and falls through to here
     959               0 :       return NS_ERROR_INVALID_ARG;
     960                 :   }
     961                 : 
     962               0 :   PRInt32 startOffset = aOffset + (aBoundaryType == BOUNDARY_LINE_END);  // Avoid getting the previous line
     963               0 :   PRInt32 endOffset = startOffset;
     964                 : 
     965                 :   // Convert offsets to frame-relative
     966               0 :   nsRefPtr<nsAccessible> startAcc;
     967                 :   nsIFrame *startFrame = GetPosAndText(startOffset, endOffset, nsnull, nsnull,
     968               0 :                                        nsnull, getter_AddRefs(startAcc));
     969                 : 
     970               0 :   if (!startFrame) {
     971               0 :     PRInt32 textLength = CharacterCount();
     972               0 :     if (aBoundaryType == BOUNDARY_LINE_START && aOffset > 0 && aOffset == textLength) {
     973                 :       // Asking for start of line, while on last character
     974               0 :       if (startAcc)
     975               0 :         startFrame = startAcc->GetFrame();
     976                 :     }
     977               0 :     if (!startFrame) {
     978               0 :       return aOffset > textLength ? NS_ERROR_FAILURE : NS_OK;
     979                 :     }
     980                 :     else {
     981                 :       // We're on the last continuation since we're on the last character
     982               0 :       startFrame = startFrame->GetLastContinuation();
     983                 :     }
     984                 :   }
     985                 : 
     986                 :   PRInt32 finalStartOffset, finalEndOffset;
     987                 : 
     988                 :   // If aType == eGetAt we'll change both the start and end offset from
     989                 :   // the original offset
     990               0 :   if (aType == eGetAfter) {
     991               0 :     finalStartOffset = aOffset;
     992                 :   }
     993                 :   else {
     994                 :     finalStartOffset = GetRelativeOffset(presShell, startFrame, startOffset,
     995                 :                                          startAcc, amount, eDirPrevious,
     996               0 :                                          needsStart);
     997               0 :     NS_ENSURE_TRUE(finalStartOffset >= 0, NS_ERROR_FAILURE);
     998                 :   }
     999                 : 
    1000               0 :   if (aType == eGetBefore) {
    1001               0 :     finalEndOffset = aOffset;
    1002                 :   }
    1003                 :   else {
    1004                 :     // Start moving forward from the start so that we don't get 
    1005                 :     // 2 words/lines if the offset occurred on whitespace boundary
    1006                 :     // Careful, startOffset and endOffset are passed by reference to GetPosAndText() and changed
    1007                 :     // For BOUNDARY_LINE_END, make sure we start of this line
    1008               0 :     startOffset = endOffset = finalStartOffset + (aBoundaryType == BOUNDARY_LINE_END);
    1009               0 :     nsRefPtr<nsAccessible> endAcc;
    1010                 :     nsIFrame *endFrame = GetPosAndText(startOffset, endOffset, nsnull, nsnull,
    1011               0 :                                        nsnull, getter_AddRefs(endAcc));
    1012               0 :     if (endAcc && endAcc->Role() == roles::STATICTEXT) {
    1013                 :       // Static text like list bullets will ruin our forward calculation,
    1014                 :       // since the caret cannot be in the static text. Start just after the static text.
    1015                 :       startOffset = endOffset = finalStartOffset +
    1016                 :                                 (aBoundaryType == BOUNDARY_LINE_END) +
    1017               0 :                                 nsAccUtils::TextLength(endAcc);
    1018                 : 
    1019                 :       endFrame = GetPosAndText(startOffset, endOffset, nsnull, nsnull,
    1020               0 :                                nsnull, getter_AddRefs(endAcc));
    1021                 :     }
    1022               0 :     if (!endFrame) {
    1023               0 :       return NS_ERROR_FAILURE;
    1024                 :     }
    1025                 :     finalEndOffset = GetRelativeOffset(presShell, endFrame, endOffset, endAcc,
    1026               0 :                                        amount, eDirNext, needsStart);
    1027               0 :     NS_ENSURE_TRUE(endOffset >= 0, NS_ERROR_FAILURE);
    1028               0 :     if (finalEndOffset == aOffset) {
    1029               0 :       if (aType == eGetAt && amount == eSelectWord) { 
    1030                 :         // Fix word error for the first character in word: PeekOffset() will return the previous word when 
    1031                 :         // aOffset points to the first character of the word, but accessibility APIs want the current word 
    1032                 :         // that the first character is in
    1033               0 :         return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
    1034                 :       }
    1035               0 :       PRInt32 textLength = CharacterCount();
    1036               0 :       if (finalEndOffset < textLength) {
    1037                 :         // This happens sometimes when current character at finalStartOffset 
    1038                 :         // is an embedded object character representing another hypertext, that
    1039                 :         // the AT really needs to dig into separately
    1040               0 :         ++ finalEndOffset;
    1041                 :       }
    1042                 :     }
    1043                 :   }
    1044                 : 
    1045               0 :   *aStartOffset = finalStartOffset;
    1046               0 :   *aEndOffset = finalEndOffset;
    1047                 : 
    1048               0 :   NS_ASSERTION((finalStartOffset < aOffset && finalEndOffset >= aOffset) || aType != eGetBefore, "Incorrect results for GetTextHelper");
    1049               0 :   NS_ASSERTION((finalStartOffset <= aOffset && finalEndOffset > aOffset) || aType == eGetBefore, "Incorrect results for GetTextHelper");
    1050                 : 
    1051               0 :   GetPosAndText(finalStartOffset, finalEndOffset, &aText);
    1052               0 :   return NS_OK;
    1053                 : }
    1054                 : 
    1055                 : /**
    1056                 :   * nsIAccessibleText impl.
    1057                 :   */
    1058               0 : NS_IMETHODIMP nsHyperTextAccessible::GetTextBeforeOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
    1059                 :                                                          PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
    1060                 : {
    1061               0 :   if (aBoundaryType == BOUNDARY_CHAR) {
    1062               0 :     GetCharAt(aOffset, eGetBefore, aText, aStartOffset, aEndOffset);
    1063               0 :     return NS_OK;
    1064                 :   }
    1065                 : 
    1066               0 :   return GetTextHelper(eGetBefore, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
    1067                 : }
    1068                 : 
    1069               0 : NS_IMETHODIMP nsHyperTextAccessible::GetTextAtOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
    1070                 :                                                      PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
    1071                 : {
    1072               0 :   if (aBoundaryType == BOUNDARY_CHAR) {
    1073               0 :     GetCharAt(aOffset, eGetAt, aText, aStartOffset, aEndOffset);
    1074               0 :     return NS_OK;
    1075                 :   }
    1076                 : 
    1077               0 :   return GetTextHelper(eGetAt, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
    1078                 : }
    1079                 : 
    1080               0 : NS_IMETHODIMP nsHyperTextAccessible::GetTextAfterOffset(PRInt32 aOffset, nsAccessibleTextBoundary aBoundaryType,
    1081                 :                                                         PRInt32 *aStartOffset, PRInt32 *aEndOffset, nsAString & aText)
    1082                 : {
    1083               0 :   if (aBoundaryType == BOUNDARY_CHAR) {
    1084               0 :     GetCharAt(aOffset, eGetAfter, aText, aStartOffset, aEndOffset);
    1085               0 :     return NS_OK;
    1086                 :   }
    1087                 : 
    1088               0 :   return GetTextHelper(eGetAfter, aBoundaryType, aOffset, aStartOffset, aEndOffset, aText);
    1089                 : }
    1090                 : 
    1091                 : // nsIPersistentProperties
    1092                 : // nsIAccessibleText::getTextAttributes(in boolean includeDefAttrs,
    1093                 : //                                      in long offset,
    1094                 : //                                      out long rangeStartOffset,
    1095                 : //                                      out long rangeEndOffset);
    1096                 : NS_IMETHODIMP
    1097               0 : nsHyperTextAccessible::GetTextAttributes(bool aIncludeDefAttrs,
    1098                 :                                          PRInt32 aOffset,
    1099                 :                                          PRInt32 *aStartOffset,
    1100                 :                                          PRInt32 *aEndOffset,
    1101                 :                                          nsIPersistentProperties **aAttributes)
    1102                 : {
    1103                 :   // 1. Get each attribute and its ranges one after another.
    1104                 :   // 2. As we get each new attribute, we pass the current start and end offsets
    1105                 :   //    as in/out parameters. In other words, as attributes are collected,
    1106                 :   //    the attribute range itself can only stay the same or get smaller.
    1107                 : 
    1108               0 :   NS_ENSURE_ARG_POINTER(aStartOffset);
    1109               0 :   *aStartOffset = 0;
    1110                 : 
    1111               0 :   NS_ENSURE_ARG_POINTER(aEndOffset);
    1112               0 :   *aEndOffset = 0;
    1113                 : 
    1114               0 :   if (IsDefunct())
    1115               0 :     return NS_ERROR_FAILURE;
    1116                 : 
    1117               0 :   if (aAttributes) {
    1118               0 :     *aAttributes = nsnull;
    1119                 : 
    1120                 :     nsCOMPtr<nsIPersistentProperties> attributes =
    1121               0 :       do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
    1122               0 :     NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
    1123                 : 
    1124               0 :     NS_ADDREF(*aAttributes = attributes);
    1125                 :   }
    1126                 : 
    1127               0 :   nsAccessible* accAtOffset = GetChildAtOffset(aOffset);
    1128               0 :   if (!accAtOffset) {
    1129                 :     // Offset 0 is correct offset when accessible has empty text. Include
    1130                 :     // default attributes if they were requested, otherwise return empty set.
    1131               0 :     if (aOffset == 0) {
    1132               0 :       if (aIncludeDefAttrs) {
    1133               0 :         TextAttrsMgr textAttrsMgr(this);
    1134               0 :         textAttrsMgr.GetAttributes(*aAttributes);
    1135                 :       }
    1136               0 :       return NS_OK;
    1137                 :     }
    1138               0 :     return NS_ERROR_INVALID_ARG;
    1139                 :   }
    1140                 : 
    1141               0 :   PRInt32 accAtOffsetIdx = accAtOffset->IndexInParent();
    1142               0 :   PRInt32 startOffset = GetChildOffset(accAtOffsetIdx);
    1143               0 :   PRInt32 endOffset = GetChildOffset(accAtOffsetIdx + 1);
    1144               0 :   PRInt32 offsetInAcc = aOffset - startOffset;
    1145                 : 
    1146                 :   TextAttrsMgr textAttrsMgr(this, aIncludeDefAttrs, accAtOffset,
    1147               0 :                             accAtOffsetIdx);
    1148               0 :   textAttrsMgr.GetAttributes(*aAttributes, &startOffset, &endOffset);
    1149                 : 
    1150                 :   // Compute spelling attributes on text accessible only.
    1151               0 :   nsIFrame *offsetFrame = accAtOffset->GetFrame();
    1152               0 :   if (offsetFrame && offsetFrame->GetType() == nsGkAtoms::textFrame) {
    1153               0 :     PRInt32 nodeOffset = 0;
    1154                 :     nsresult rv = RenderedToContentOffset(offsetFrame, offsetInAcc,
    1155               0 :                                           &nodeOffset);
    1156               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1157                 : 
    1158                 :     // Set 'misspelled' text attribute.
    1159               0 :     rv = GetSpellTextAttribute(accAtOffset->GetNode(), nodeOffset,
    1160                 :                                &startOffset, &endOffset,
    1161               0 :                                aAttributes ? *aAttributes : nsnull);
    1162               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1163                 :   }
    1164                 : 
    1165               0 :   *aStartOffset = startOffset;
    1166               0 :   *aEndOffset = endOffset;
    1167               0 :   return NS_OK;
    1168                 : }
    1169                 : 
    1170                 : // nsIPersistentProperties
    1171                 : // nsIAccessibleText::defaultTextAttributes
    1172                 : NS_IMETHODIMP
    1173               0 : nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttributes)
    1174                 : {
    1175               0 :   NS_ENSURE_ARG_POINTER(aAttributes);
    1176               0 :   *aAttributes = nsnull;
    1177                 : 
    1178               0 :   if (IsDefunct())
    1179               0 :     return NS_ERROR_FAILURE;
    1180                 : 
    1181                 :   nsCOMPtr<nsIPersistentProperties> attributes =
    1182               0 :     do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
    1183               0 :   NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
    1184                 : 
    1185               0 :   NS_ADDREF(*aAttributes = attributes);
    1186                 : 
    1187               0 :   TextAttrsMgr textAttrsMgr(this);
    1188               0 :   textAttrsMgr.GetAttributes(*aAttributes);
    1189               0 :   return NS_OK;
    1190                 : }
    1191                 : 
    1192                 : PRInt32
    1193               0 : nsHyperTextAccessible::GetLevelInternal()
    1194                 : {
    1195               0 :   nsIAtom *tag = mContent->Tag();
    1196               0 :   if (tag == nsGkAtoms::h1)
    1197               0 :     return 1;
    1198               0 :   if (tag == nsGkAtoms::h2)
    1199               0 :     return 2;
    1200               0 :   if (tag == nsGkAtoms::h3)
    1201               0 :     return 3;
    1202               0 :   if (tag == nsGkAtoms::h4)
    1203               0 :     return 4;
    1204               0 :   if (tag == nsGkAtoms::h5)
    1205               0 :     return 5;
    1206               0 :   if (tag == nsGkAtoms::h6)
    1207               0 :     return 6;
    1208                 : 
    1209               0 :   return nsAccessibleWrap::GetLevelInternal();
    1210                 : }
    1211                 : 
    1212                 : nsresult
    1213               0 : nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
    1214                 : {
    1215               0 :   nsresult rv = nsAccessibleWrap::GetAttributesInternal(aAttributes);
    1216               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1217                 : 
    1218                 :   // Indicate when the current object uses block-level formatting
    1219                 :   // via formatting: block
    1220                 :   // XXX: 'formatting' attribute is deprecated and will be removed in Mozilla2,
    1221                 :   // use 'display' attribute instead.
    1222               0 :   nsIFrame *frame = GetFrame();
    1223               0 :   if (frame && frame->GetType() == nsGkAtoms::blockFrame) {
    1224               0 :     nsAutoString oldValueUnused;
    1225               0 :     aAttributes->SetStringProperty(NS_LITERAL_CSTRING("formatting"), NS_LITERAL_STRING("block"),
    1226               0 :                                    oldValueUnused);
    1227                 :   }
    1228                 : 
    1229               0 :   if (FocusMgr()->IsFocused(this)) {
    1230               0 :     PRInt32 lineNumber = GetCaretLineNumber();
    1231               0 :     if (lineNumber >= 1) {
    1232               0 :       nsAutoString strLineNumber;
    1233               0 :       strLineNumber.AppendInt(lineNumber);
    1234                 :       nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::lineNumber,
    1235               0 :                              strLineNumber);
    1236                 :     }
    1237                 :   }
    1238                 : 
    1239                 :   // For the html landmark elements we expose them like we do aria landmarks to
    1240                 :   // make AT navigation schemes "just work". Note html:header is redundant as
    1241                 :   // a landmark since it usually contains headings. We're not yet sure how the
    1242                 :   // web will use html:footer but our best bet right now is as contentinfo.
    1243               0 :   if (mContent->Tag() == nsGkAtoms::nav)
    1244                 :     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
    1245               0 :                            NS_LITERAL_STRING("navigation"));
    1246               0 :   else if (mContent->Tag() == nsGkAtoms::footer) 
    1247                 :     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
    1248               0 :                            NS_LITERAL_STRING("contentinfo"));
    1249               0 :   else if (mContent->Tag() == nsGkAtoms::aside) 
    1250                 :     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
    1251               0 :                            NS_LITERAL_STRING("complementary"));
    1252                 : 
    1253               0 :   return  NS_OK;
    1254                 : }
    1255                 : 
    1256                 : /*
    1257                 :  * Given an offset, the x, y, width, and height values are filled appropriately.
    1258                 :  */
    1259               0 : NS_IMETHODIMP nsHyperTextAccessible::GetCharacterExtents(PRInt32 aOffset, PRInt32 *aX, PRInt32 *aY,
    1260                 :                                                          PRInt32 *aWidth, PRInt32 *aHeight,
    1261                 :                                                          PRUint32 aCoordType)
    1262                 : {
    1263               0 :   return GetRangeExtents(aOffset, aOffset + 1, aX, aY, aWidth, aHeight, aCoordType);
    1264                 : }
    1265                 : 
    1266                 : /*
    1267                 :  * Given a start & end offset, the x, y, width, and height values are filled appropriately.
    1268                 :  */
    1269               0 : NS_IMETHODIMP nsHyperTextAccessible::GetRangeExtents(PRInt32 aStartOffset, PRInt32 aEndOffset,
    1270                 :                                                      PRInt32 *aX, PRInt32 *aY,
    1271                 :                                                      PRInt32 *aWidth, PRInt32 *aHeight,
    1272                 :                                                      PRUint32 aCoordType)
    1273                 : {
    1274               0 :   nsIntRect boundsRect;
    1275                 :   nsIFrame *endFrameUnused;
    1276               0 :   if (!GetPosAndText(aStartOffset, aEndOffset, nsnull, &endFrameUnused, &boundsRect) ||
    1277               0 :       boundsRect.IsEmpty()) {
    1278               0 :     return NS_ERROR_FAILURE;
    1279                 :   }
    1280                 : 
    1281               0 :   *aX = boundsRect.x;
    1282               0 :   *aY = boundsRect.y;
    1283               0 :   *aWidth = boundsRect.width;
    1284               0 :   *aHeight = boundsRect.height;
    1285                 : 
    1286               0 :   return nsAccUtils::ConvertScreenCoordsTo(aX, aY, aCoordType, this);
    1287                 : }
    1288                 : 
    1289                 : /*
    1290                 :  * Gets the offset of the character located at coordinates x and y. x and y are interpreted as being relative to
    1291                 :  * the screen or this widget's window depending on coords.
    1292                 :  */
    1293                 : NS_IMETHODIMP
    1294               0 : nsHyperTextAccessible::GetOffsetAtPoint(PRInt32 aX, PRInt32 aY,
    1295                 :                                         PRUint32 aCoordType, PRInt32 *aOffset)
    1296                 : {
    1297               0 :   *aOffset = -1;
    1298               0 :   if (!mDoc)
    1299               0 :     return NS_ERROR_FAILURE;
    1300                 : 
    1301               0 :   nsIPresShell* shell = mDoc->PresShell();
    1302               0 :   if (!shell) {
    1303               0 :     return NS_ERROR_FAILURE;
    1304                 :   }
    1305               0 :   nsIFrame *hyperFrame = GetFrame();
    1306               0 :   if (!hyperFrame) {
    1307               0 :     return NS_ERROR_FAILURE;
    1308                 :   }
    1309               0 :   nsIntRect frameScreenRect = hyperFrame->GetScreenRectExternal();
    1310                 : 
    1311               0 :   nsIntPoint coords;
    1312                 :   nsresult rv = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordType,
    1313               0 :                                                   this, &coords);
    1314               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1315                 : 
    1316                 :   // coords are currently screen coordinates, and we need to turn them into
    1317                 :   // frame coordinates relative to the current accessible
    1318               0 :   if (!frameScreenRect.Contains(coords.x, coords.y)) {
    1319               0 :     return NS_OK;   // Not found, will return -1
    1320                 :   }
    1321                 :   nsIntPoint pxInHyperText(coords.x - frameScreenRect.x,
    1322               0 :                            coords.y - frameScreenRect.y);
    1323               0 :   nsPresContext *context = GetPresContext();
    1324               0 :   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
    1325                 :   nsPoint pointInHyperText(context->DevPixelsToAppUnits(pxInHyperText.x),
    1326               0 :                            context->DevPixelsToAppUnits(pxInHyperText.y));
    1327                 : 
    1328                 :   // Go through the frames to check if each one has the point.
    1329                 :   // When one does, add up the character offsets until we have a match
    1330                 : 
    1331                 :   // We have an point in an accessible child of this, now we need to add up the
    1332                 :   // offsets before it to what we already have
    1333               0 :   PRInt32 offset = 0;
    1334               0 :   PRInt32 childCount = GetChildCount();
    1335               0 :   for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
    1336               0 :     nsAccessible *childAcc = mChildren[childIdx];
    1337                 : 
    1338               0 :     nsIFrame *primaryFrame = childAcc->GetFrame();
    1339               0 :     NS_ENSURE_TRUE(primaryFrame, NS_ERROR_FAILURE);
    1340                 : 
    1341               0 :     nsIFrame *frame = primaryFrame;
    1342               0 :     while (frame) {
    1343               0 :       nsIContent *content = frame->GetContent();
    1344               0 :       NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
    1345               0 :       nsPoint pointInFrame = pointInHyperText - frame->GetOffsetToExternal(hyperFrame);
    1346               0 :       nsSize frameSize = frame->GetSize();
    1347               0 :       if (pointInFrame.x < frameSize.width && pointInFrame.y < frameSize.height) {
    1348                 :         // Finished
    1349               0 :         if (frame->GetType() == nsGkAtoms::textFrame) {
    1350               0 :           nsIFrame::ContentOffsets contentOffsets = frame->GetContentOffsetsFromPointExternal(pointInFrame, true);
    1351               0 :           if (contentOffsets.IsNull() || contentOffsets.content != content) {
    1352               0 :             return NS_OK; // Not found, will return -1
    1353                 :           }
    1354                 :           PRUint32 addToOffset;
    1355                 :           nsresult rv = ContentToRenderedOffset(primaryFrame,
    1356                 :                                                 contentOffsets.offset,
    1357               0 :                                                 &addToOffset);
    1358               0 :           NS_ENSURE_SUCCESS(rv, rv);
    1359               0 :           offset += addToOffset;
    1360                 :         }
    1361               0 :         *aOffset = offset;
    1362               0 :         return NS_OK;
    1363                 :       }
    1364               0 :       frame = frame->GetNextContinuation();
    1365                 :     }
    1366                 : 
    1367               0 :     offset += nsAccUtils::TextLength(childAcc);
    1368                 :   }
    1369                 : 
    1370               0 :   return NS_OK; // Not found, will return -1
    1371                 : }
    1372                 : 
    1373                 : 
    1374                 : ////////////////////////////////////////////////////////////////////////////////
    1375                 : // nsIAccessibleHyperText
    1376                 : 
    1377                 : NS_IMETHODIMP
    1378               0 : nsHyperTextAccessible::GetLinkCount(PRInt32 *aLinkCount)
    1379                 : {
    1380               0 :   NS_ENSURE_ARG_POINTER(aLinkCount);
    1381               0 :   *aLinkCount = 0;
    1382                 : 
    1383               0 :   if (IsDefunct())
    1384               0 :     return NS_ERROR_FAILURE;
    1385                 : 
    1386               0 :   *aLinkCount = GetLinkCount();
    1387               0 :   return NS_OK;
    1388                 : }
    1389                 : 
    1390                 : NS_IMETHODIMP
    1391               0 : nsHyperTextAccessible::GetLinkAt(PRInt32 aIndex, nsIAccessibleHyperLink** aLink)
    1392                 : {
    1393               0 :   NS_ENSURE_ARG_POINTER(aLink);
    1394               0 :   *aLink = nsnull;
    1395                 : 
    1396               0 :   if (IsDefunct())
    1397               0 :     return NS_ERROR_FAILURE;
    1398                 : 
    1399               0 :   nsAccessible* link = GetLinkAt(aIndex);
    1400               0 :   if (link)
    1401               0 :     CallQueryInterface(link, aLink);
    1402                 : 
    1403               0 :   return NS_OK;
    1404                 : }
    1405                 : 
    1406                 : NS_IMETHODIMP
    1407               0 : nsHyperTextAccessible::GetLinkIndex(nsIAccessibleHyperLink* aLink,
    1408                 :                                     PRInt32* aIndex)
    1409                 : {
    1410               0 :   NS_ENSURE_ARG_POINTER(aLink);
    1411                 : 
    1412               0 :   if (IsDefunct())
    1413               0 :     return NS_ERROR_FAILURE;
    1414                 : 
    1415               0 :   nsRefPtr<nsAccessible> link(do_QueryObject(aLink));
    1416               0 :   *aIndex = GetLinkIndex(link);
    1417               0 :   return NS_OK;
    1418                 : }
    1419                 : 
    1420                 : NS_IMETHODIMP
    1421               0 : nsHyperTextAccessible::GetLinkIndexAtOffset(PRInt32 aOffset,
    1422                 :                                             PRInt32* aLinkIndex)
    1423                 : {
    1424               0 :   NS_ENSURE_ARG_POINTER(aLinkIndex);
    1425               0 :   *aLinkIndex = -1; // API says this magic value means 'not found'
    1426                 : 
    1427               0 :   if (IsDefunct())
    1428               0 :     return NS_ERROR_FAILURE;
    1429                 : 
    1430               0 :   *aLinkIndex = GetLinkIndexAtOffset(aOffset);
    1431               0 :   return NS_OK;
    1432                 : }
    1433                 : 
    1434                 : /**
    1435                 :   * nsIAccessibleEditableText impl.
    1436                 :   */
    1437               0 : NS_IMETHODIMP nsHyperTextAccessible::SetAttributes(PRInt32 aStartPos, PRInt32 aEndPos,
    1438                 :                                                    nsISupports *aAttributes)
    1439                 : {
    1440               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    1441                 : }
    1442                 : 
    1443               0 : NS_IMETHODIMP nsHyperTextAccessible::SetTextContents(const nsAString &aText)
    1444                 : {
    1445               0 :   PRInt32 numChars = CharacterCount();
    1446               0 :   if (numChars == 0 || NS_SUCCEEDED(DeleteText(0, numChars))) {
    1447               0 :     return InsertText(aText, 0);
    1448                 :   }
    1449               0 :   return NS_ERROR_FAILURE;
    1450                 : }
    1451                 : 
    1452                 : NS_IMETHODIMP
    1453               0 : nsHyperTextAccessible::InsertText(const nsAString &aText, PRInt32 aPosition)
    1454                 : {
    1455               0 :   if (IsDefunct())
    1456               0 :     return NS_ERROR_FAILURE;
    1457                 : 
    1458               0 :   nsCOMPtr<nsIEditor> editor = GetEditor();
    1459                 : 
    1460               0 :   nsCOMPtr<nsIPlaintextEditor> peditor(do_QueryInterface(editor));
    1461               0 :   NS_ENSURE_STATE(peditor);
    1462                 : 
    1463               0 :   nsresult rv = SetSelectionRange(aPosition, aPosition);
    1464               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1465                 : 
    1466               0 :   return peditor->InsertText(aText);
    1467                 : }
    1468                 : 
    1469                 : NS_IMETHODIMP
    1470               0 : nsHyperTextAccessible::CopyText(PRInt32 aStartPos, PRInt32 aEndPos)
    1471                 : {
    1472               0 :   if (IsDefunct())
    1473               0 :     return NS_ERROR_FAILURE;
    1474                 : 
    1475               0 :   nsCOMPtr<nsIEditor> editor = GetEditor();
    1476               0 :   NS_ENSURE_STATE(editor);
    1477                 : 
    1478               0 :   nsresult rv = SetSelectionRange(aStartPos, aEndPos);
    1479               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1480                 : 
    1481               0 :   return editor->Copy();
    1482                 : }
    1483                 : 
    1484                 : NS_IMETHODIMP
    1485               0 : nsHyperTextAccessible::CutText(PRInt32 aStartPos, PRInt32 aEndPos)
    1486                 : {
    1487               0 :   if (IsDefunct())
    1488               0 :     return NS_ERROR_FAILURE;
    1489                 : 
    1490               0 :   nsCOMPtr<nsIEditor> editor = GetEditor();
    1491               0 :   NS_ENSURE_STATE(editor);
    1492                 : 
    1493               0 :   nsresult rv = SetSelectionRange(aStartPos, aEndPos);
    1494               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1495                 : 
    1496               0 :   return editor->Cut();
    1497                 : }
    1498                 : 
    1499                 : NS_IMETHODIMP
    1500               0 : nsHyperTextAccessible::DeleteText(PRInt32 aStartPos, PRInt32 aEndPos)
    1501                 : {
    1502               0 :   if (IsDefunct())
    1503               0 :     return NS_ERROR_FAILURE;
    1504                 : 
    1505               0 :   nsCOMPtr<nsIEditor> editor = GetEditor();
    1506               0 :   NS_ENSURE_STATE(editor);
    1507                 : 
    1508               0 :   nsresult rv = SetSelectionRange(aStartPos, aEndPos);
    1509               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1510                 : 
    1511               0 :   return editor->DeleteSelection(nsIEditor::eNone);
    1512                 : }
    1513                 : 
    1514                 : NS_IMETHODIMP
    1515               0 : nsHyperTextAccessible::PasteText(PRInt32 aPosition)
    1516                 : {
    1517               0 :   if (IsDefunct())
    1518               0 :     return NS_ERROR_FAILURE;
    1519                 : 
    1520               0 :   nsCOMPtr<nsIEditor> editor = GetEditor();
    1521               0 :   NS_ENSURE_STATE(editor);
    1522                 : 
    1523               0 :   nsresult rv = SetSelectionRange(aPosition, aPosition);
    1524               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1525                 : 
    1526               0 :   return editor->Paste(nsIClipboard::kGlobalClipboard);
    1527                 : }
    1528                 : 
    1529                 : already_AddRefed<nsIEditor>
    1530               0 : nsHyperTextAccessible::GetEditor() const
    1531                 : {
    1532               0 :   if (!mContent->HasFlag(NODE_IS_EDITABLE)) {
    1533                 :     // If we're inside an editable container, then return that container's editor
    1534               0 :     nsAccessible* ancestor = Parent();
    1535               0 :     while (ancestor) {
    1536               0 :       nsHyperTextAccessible* hyperText = ancestor->AsHyperText();
    1537               0 :       if (hyperText) {
    1538                 :         // Recursion will stop at container doc because it has its own impl
    1539                 :         // of GetEditor()
    1540               0 :         return hyperText->GetEditor();
    1541                 :       }
    1542                 : 
    1543               0 :       ancestor = ancestor->Parent();
    1544                 :     }
    1545                 : 
    1546               0 :     return nsnull;
    1547                 :   }
    1548                 : 
    1549                 :   nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
    1550               0 :     nsCoreUtils::GetDocShellTreeItemFor(mContent);
    1551               0 :   nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShellTreeItem));
    1552               0 :   if (!editingSession)
    1553               0 :     return nsnull; // No editing session interface
    1554                 : 
    1555               0 :   nsCOMPtr<nsIEditor> editor;
    1556               0 :   nsIDocument* docNode = mDoc->GetDocumentNode();
    1557               0 :   editingSession->GetEditorForWindow(docNode->GetWindow(),
    1558               0 :                                      getter_AddRefs(editor));
    1559               0 :   return editor.forget();
    1560                 : }
    1561                 : 
    1562                 : /**
    1563                 :   * =================== Caret & Selection ======================
    1564                 :   */
    1565                 : 
    1566                 : nsresult
    1567               0 : nsHyperTextAccessible::SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos)
    1568                 : {
    1569               0 :   bool isFocusable = State() & states::FOCUSABLE;
    1570                 : 
    1571                 :   // If accessible is focusable then focus it before setting the selection to
    1572                 :   // neglect control's selection changes on focus if any (for example, inputs
    1573                 :   // that do select all on focus).
    1574                 :   // some input controls
    1575               0 :   if (isFocusable)
    1576               0 :     TakeFocus();
    1577                 : 
    1578                 :   // Set the selection
    1579               0 :   SetSelectionBounds(0, aStartPos, aEndPos);
    1580                 : 
    1581                 :   // If range 0 was successfully set, clear any additional selection 
    1582                 :   // ranges remaining from previous selection
    1583               0 :   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
    1584               0 :   NS_ENSURE_STATE(frameSelection);
    1585                 : 
    1586                 :   nsCOMPtr<nsISelection> domSel =
    1587               0 :     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
    1588               0 :   NS_ENSURE_STATE(domSel);
    1589                 : 
    1590               0 :   PRInt32 numRanges = 0;
    1591               0 :   domSel->GetRangeCount(&numRanges);
    1592                 : 
    1593               0 :   for (PRInt32 count = 0; count < numRanges - 1; count ++) {
    1594               0 :     nsCOMPtr<nsIDOMRange> range;
    1595               0 :     domSel->GetRangeAt(1, getter_AddRefs(range));
    1596               0 :     domSel->RemoveRange(range);
    1597                 :   }
    1598                 : 
    1599                 :   // When selection is done, move the focus to the selection if accessible is
    1600                 :   // not focusable. That happens when selection is set within hypertext
    1601                 :   // accessible.
    1602               0 :   if (isFocusable)
    1603               0 :     return NS_OK;
    1604                 : 
    1605               0 :   nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager();
    1606               0 :   if (DOMFocusManager) {
    1607               0 :     NS_ENSURE_TRUE(mDoc, NS_ERROR_FAILURE);
    1608               0 :     nsIDocument* docNode = mDoc->GetDocumentNode();
    1609               0 :     NS_ENSURE_TRUE(docNode, NS_ERROR_FAILURE);
    1610               0 :     nsCOMPtr<nsPIDOMWindow> window = docNode->GetWindow();
    1611               0 :     nsCOMPtr<nsIDOMElement> result;
    1612                 :     DOMFocusManager->MoveFocus(window, nsnull, nsIFocusManager::MOVEFOCUS_CARET,
    1613               0 :                                nsIFocusManager::FLAG_BYMOVEFOCUS, getter_AddRefs(result));
    1614                 :   }
    1615                 : 
    1616               0 :   return NS_OK;
    1617                 : }
    1618                 : 
    1619                 : NS_IMETHODIMP
    1620               0 : nsHyperTextAccessible::SetCaretOffset(PRInt32 aCaretOffset)
    1621                 : {
    1622               0 :   return SetSelectionRange(aCaretOffset, aCaretOffset);
    1623                 : }
    1624                 : 
    1625                 : /*
    1626                 :  * Gets the offset position of the caret (cursor).
    1627                 :  */
    1628                 : NS_IMETHODIMP
    1629               0 : nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
    1630                 : {
    1631               0 :   NS_ENSURE_ARG_POINTER(aCaretOffset);
    1632               0 :   *aCaretOffset = -1;
    1633                 : 
    1634               0 :   if (IsDefunct())
    1635               0 :     return NS_ERROR_FAILURE;
    1636                 : 
    1637                 :   // Not focused focusable accessible except document accessible doesn't have
    1638                 :   // a caret.
    1639               0 :   if (!IsDoc() && !FocusMgr()->IsFocused(this) &&
    1640               0 :       (State() & states::FOCUSABLE)) {
    1641               0 :     return NS_OK;
    1642                 :   }
    1643                 : 
    1644                 :   // No caret if the focused node is not inside this DOM node and this DOM node
    1645                 :   // is not inside of focused node.
    1646                 :   FocusManager::FocusDisposition focusDisp =
    1647               0 :     FocusMgr()->IsInOrContainsFocus(this);
    1648               0 :   if (focusDisp == FocusManager::eNone)
    1649               0 :     return NS_OK;
    1650                 : 
    1651                 :   // Turn the focus node and offset of the selection into caret hypretext
    1652                 :   // offset.
    1653               0 :   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
    1654               0 :   NS_ENSURE_STATE(frameSelection);
    1655                 : 
    1656                 :   nsISelection* domSel =
    1657               0 :     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
    1658               0 :   NS_ENSURE_STATE(domSel);
    1659                 : 
    1660               0 :   nsCOMPtr<nsIDOMNode> focusDOMNode;
    1661               0 :   nsresult rv = domSel->GetFocusNode(getter_AddRefs(focusDOMNode));
    1662               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1663                 : 
    1664                 :   PRInt32 focusOffset;
    1665               0 :   rv = domSel->GetFocusOffset(&focusOffset);
    1666               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1667                 : 
    1668                 :   // No caret if this DOM node is inside of focused node but the selection's
    1669                 :   // focus point is not inside of this DOM node.
    1670               0 :   nsCOMPtr<nsINode> focusNode(do_QueryInterface(focusDOMNode));
    1671               0 :   if (focusDisp == FocusManager::eContainedByFocus) {
    1672                 :     nsINode *resultNode =
    1673               0 :       nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
    1674                 : 
    1675               0 :     nsINode* thisNode = GetNode();
    1676               0 :     if (resultNode != thisNode &&
    1677               0 :         !nsCoreUtils::IsAncestorOf(thisNode, resultNode))
    1678               0 :       return NS_OK;
    1679                 :   }
    1680                 : 
    1681               0 :   DOMPointToHypertextOffset(focusNode, focusOffset, aCaretOffset);
    1682               0 :   return NS_OK;
    1683                 : }
    1684                 : 
    1685                 : PRInt32
    1686               0 : nsHyperTextAccessible::GetCaretLineNumber()
    1687                 : {
    1688                 :   // Provide the line number for the caret, relative to the
    1689                 :   // currently focused node. Use a 1-based index
    1690               0 :   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
    1691               0 :   if (!frameSelection)
    1692               0 :     return -1;
    1693                 : 
    1694                 :   nsISelection* domSel =
    1695               0 :     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
    1696               0 :   if (!domSel)
    1697               0 :     return - 1;
    1698                 : 
    1699               0 :   nsCOMPtr<nsIDOMNode> caretNode;
    1700               0 :   domSel->GetFocusNode(getter_AddRefs(caretNode));
    1701               0 :   nsCOMPtr<nsIContent> caretContent = do_QueryInterface(caretNode);
    1702               0 :   if (!caretContent || !nsCoreUtils::IsAncestorOf(GetNode(), caretContent))
    1703               0 :     return -1;
    1704                 : 
    1705                 :   PRInt32 caretOffset, returnOffsetUnused;
    1706               0 :   domSel->GetFocusOffset(&caretOffset);
    1707               0 :   nsFrameSelection::HINT hint = frameSelection->GetHint();
    1708               0 :   nsIFrame *caretFrame = frameSelection->GetFrameForNodeOffset(caretContent, caretOffset,
    1709               0 :                                                                hint, &returnOffsetUnused);
    1710               0 :   NS_ENSURE_TRUE(caretFrame, -1);
    1711                 : 
    1712               0 :   PRInt32 lineNumber = 1;
    1713               0 :   nsAutoLineIterator lineIterForCaret;
    1714               0 :   nsIContent *hyperTextContent = IsContent() ? mContent.get() : nsnull;
    1715               0 :   while (caretFrame) {
    1716               0 :     if (hyperTextContent == caretFrame->GetContent()) {
    1717               0 :       return lineNumber; // Must be in a single line hyper text, there is no line iterator
    1718                 :     }
    1719               0 :     nsIFrame *parentFrame = caretFrame->GetParent();
    1720               0 :     if (!parentFrame)
    1721               0 :       break;
    1722                 : 
    1723                 :     // Add lines for the sibling frames before the caret
    1724               0 :     nsIFrame *sibling = parentFrame->GetFirstPrincipalChild();
    1725               0 :     while (sibling && sibling != caretFrame) {
    1726               0 :       nsAutoLineIterator lineIterForSibling = sibling->GetLineIterator();
    1727               0 :       if (lineIterForSibling) {
    1728                 :         // For the frames before that grab all the lines
    1729               0 :         PRInt32 addLines = lineIterForSibling->GetNumLines();
    1730               0 :         lineNumber += addLines;
    1731                 :       }
    1732               0 :       sibling = sibling->GetNextSibling();
    1733                 :     }
    1734                 : 
    1735                 :     // Get the line number relative to the container with lines
    1736               0 :     if (!lineIterForCaret) {   // Add the caret line just once
    1737               0 :       lineIterForCaret = parentFrame->GetLineIterator();
    1738               0 :       if (lineIterForCaret) {
    1739                 :         // Ancestor of caret
    1740               0 :         PRInt32 addLines = lineIterForCaret->FindLineContaining(caretFrame);
    1741               0 :         lineNumber += addLines;
    1742                 :       }
    1743                 :     }
    1744                 : 
    1745               0 :     caretFrame = parentFrame;
    1746                 :   }
    1747                 : 
    1748               0 :   NS_NOTREACHED("DOM ancestry had this hypertext but frame ancestry didn't");
    1749               0 :   return lineNumber;
    1750                 : }
    1751                 : 
    1752                 : already_AddRefed<nsFrameSelection>
    1753               0 : nsHyperTextAccessible::FrameSelection()
    1754                 : {
    1755               0 :   nsIFrame* frame = GetFrame();
    1756               0 :   return frame ? frame->GetFrameSelection() : nsnull;
    1757                 : }
    1758                 : 
    1759                 : void
    1760               0 : nsHyperTextAccessible::GetSelectionDOMRanges(PRInt16 aType,
    1761                 :                                              nsTArray<nsRange*>* aRanges)
    1762                 : {
    1763               0 :   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
    1764               0 :   if (!frameSelection)
    1765                 :     return;
    1766                 : 
    1767               0 :   nsISelection* domSel = frameSelection->GetSelection(aType);
    1768               0 :   if (!domSel)
    1769                 :     return;
    1770                 : 
    1771               0 :   nsCOMPtr<nsINode> startNode = GetNode();
    1772                 : 
    1773               0 :   nsCOMPtr<nsIEditor> editor = GetEditor();
    1774               0 :   if (editor) {
    1775               0 :     nsCOMPtr<nsIDOMElement> editorRoot;
    1776               0 :     editor->GetRootElement(getter_AddRefs(editorRoot));
    1777               0 :     startNode = do_QueryInterface(editorRoot);
    1778                 :   }
    1779                 : 
    1780               0 :   if (!startNode)
    1781                 :     return;
    1782                 : 
    1783               0 :   PRUint32 childCount = startNode->GetChildCount();
    1784               0 :   nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(domSel));
    1785               0 :   nsresult rv = privSel->
    1786               0 :     GetRangesForIntervalArray(startNode, 0, startNode, childCount, true, aRanges);
    1787               0 :   NS_ENSURE_SUCCESS(rv,);
    1788                 : 
    1789                 :   // Remove collapsed ranges
    1790               0 :   PRUint32 numRanges = aRanges->Length();
    1791               0 :   for (PRUint32 idx = 0; idx < numRanges; idx ++) {
    1792               0 :     if ((*aRanges)[idx]->Collapsed()) {
    1793               0 :       aRanges->RemoveElementAt(idx);
    1794               0 :       --numRanges;
    1795               0 :       --idx;
    1796                 :     }
    1797                 :   }
    1798                 : }
    1799                 : 
    1800                 : /*
    1801                 :  * Gets the number of selected regions.
    1802                 :  */
    1803                 : NS_IMETHODIMP
    1804               0 : nsHyperTextAccessible::GetSelectionCount(PRInt32* aSelectionCount)
    1805                 : {
    1806               0 :   NS_ENSURE_ARG_POINTER(aSelectionCount);
    1807               0 :   *aSelectionCount = 0;
    1808                 : 
    1809               0 :   nsTArray<nsRange*> ranges;
    1810               0 :   GetSelectionDOMRanges(nsISelectionController::SELECTION_NORMAL, &ranges);
    1811               0 :   *aSelectionCount = PRInt32(ranges.Length());
    1812                 : 
    1813               0 :   return NS_OK;
    1814                 : }
    1815                 : 
    1816                 : /*
    1817                 :  * Gets the start and end offset of the specified selection.
    1818                 :  */
    1819                 : NS_IMETHODIMP
    1820               0 : nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum,
    1821                 :                                           PRInt32* aStartOffset,
    1822                 :                                           PRInt32* aEndOffset)
    1823                 : {
    1824               0 :   NS_ENSURE_ARG_POINTER(aStartOffset);
    1825               0 :   NS_ENSURE_ARG_POINTER(aEndOffset);
    1826               0 :   *aStartOffset = *aEndOffset = 0;
    1827                 : 
    1828               0 :   nsTArray<nsRange*> ranges;
    1829               0 :   GetSelectionDOMRanges(nsISelectionController::SELECTION_NORMAL, &ranges);
    1830                 : 
    1831               0 :   PRUint32 rangeCount = ranges.Length();
    1832               0 :   if (aSelectionNum < 0 || aSelectionNum >= rangeCount)
    1833               0 :     return NS_ERROR_INVALID_ARG;
    1834                 : 
    1835               0 :   nsRange* range = ranges[aSelectionNum];
    1836                 : 
    1837                 :   // Get start and end points.
    1838               0 :   nsINode* startNode = range->GetStartParent();
    1839               0 :   nsINode* endNode = range->GetEndParent();
    1840               0 :   PRInt32 startOffset = range->StartOffset(), endOffset = range->EndOffset();
    1841                 : 
    1842                 :   // Make sure start is before end, by swapping DOM points.  This occurs when
    1843                 :   // the user selects backwards in the text.
    1844                 :   PRInt32 rangeCompare = nsContentUtils::ComparePoints(endNode, endOffset,
    1845               0 :                                                        startNode, startOffset);
    1846               0 :   if (rangeCompare < 0) {
    1847               0 :     nsINode* tempNode = startNode;
    1848               0 :     startNode = endNode;
    1849               0 :     endNode = tempNode;
    1850               0 :     PRInt32 tempOffset = startOffset;
    1851               0 :     startOffset = endOffset;
    1852               0 :     endOffset = tempOffset;
    1853                 :   }
    1854                 : 
    1855                 :   nsAccessible *startAccessible =
    1856               0 :     DOMPointToHypertextOffset(startNode, startOffset, aStartOffset);
    1857               0 :   if (!startAccessible) {
    1858               0 :     *aStartOffset = 0; // Could not find start point within this hypertext, so starts before
    1859                 :   }
    1860                 : 
    1861               0 :   DOMPointToHypertextOffset(endNode, endOffset, aEndOffset, true);
    1862               0 :   return NS_OK;
    1863                 : }
    1864                 : 
    1865                 : /*
    1866                 :  * Changes the start and end offset of the specified selection.
    1867                 :  */
    1868                 : NS_IMETHODIMP
    1869               0 : nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum,
    1870                 :                                           PRInt32 aStartOffset,
    1871                 :                                           PRInt32 aEndOffset)
    1872                 : {
    1873               0 :   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
    1874               0 :   NS_ENSURE_STATE(frameSelection);
    1875                 : 
    1876                 :   nsCOMPtr<nsISelection> domSel =
    1877               0 :     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
    1878               0 :   NS_ENSURE_STATE(domSel);
    1879                 : 
    1880                 :   // Caret is a collapsed selection
    1881               0 :   bool isOnlyCaret = (aStartOffset == aEndOffset);
    1882                 : 
    1883               0 :   PRInt32 rangeCount = 0;
    1884               0 :   domSel->GetRangeCount(&rangeCount);
    1885               0 :   nsCOMPtr<nsIDOMRange> range;
    1886               0 :   if (aSelectionNum == rangeCount) { // Add a range
    1887               0 :     range = new nsRange();
    1888                 :   }
    1889               0 :   else if (aSelectionNum < 0 || aSelectionNum > rangeCount) {
    1890               0 :     return NS_ERROR_INVALID_ARG;
    1891                 :   }
    1892                 :   else {
    1893               0 :     domSel->GetRangeAt(aSelectionNum, getter_AddRefs(range));
    1894               0 :     NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
    1895                 :   }
    1896                 : 
    1897               0 :   PRInt32 startOffset = 0, endOffset = 0;
    1898               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
    1899                 : 
    1900                 :   nsresult rv = HypertextOffsetsToDOMRange(aStartOffset, aEndOffset,
    1901               0 :                                            getter_AddRefs(startNode), &startOffset,
    1902               0 :                                            getter_AddRefs(endNode), &endOffset);
    1903               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1904                 : 
    1905               0 :   rv = range->SetStart(startNode, startOffset);
    1906               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1907                 : 
    1908               0 :   rv = isOnlyCaret ? range->Collapse(true) :
    1909               0 :                      range->SetEnd(endNode, endOffset);
    1910               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1911                 : 
    1912                 :   // If new range was created then add it, otherwise notify selection listeners
    1913                 :   // that existing selection range was changed.
    1914               0 :   if (aSelectionNum == rangeCount)
    1915               0 :     return domSel->AddRange(range);
    1916                 : 
    1917               0 :   domSel->RemoveRange(range);
    1918               0 :   domSel->AddRange(range);
    1919               0 :   return NS_OK;
    1920                 : }
    1921                 : 
    1922                 : /*
    1923                 :  * Adds a selection bounded by the specified offsets.
    1924                 :  */
    1925                 : NS_IMETHODIMP
    1926               0 : nsHyperTextAccessible::AddSelection(PRInt32 aStartOffset, PRInt32 aEndOffset)
    1927                 : {
    1928               0 :   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
    1929               0 :   NS_ENSURE_STATE(frameSelection);
    1930                 : 
    1931                 :   nsCOMPtr<nsISelection> domSel =
    1932               0 :     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
    1933               0 :   NS_ENSURE_STATE(domSel);
    1934                 : 
    1935               0 :   PRInt32 rangeCount = 0;
    1936               0 :   domSel->GetRangeCount(&rangeCount);
    1937                 : 
    1938               0 :   return SetSelectionBounds(rangeCount, aStartOffset, aEndOffset);
    1939                 : }
    1940                 : 
    1941                 : /*
    1942                 :  * Removes the specified selection.
    1943                 :  */
    1944                 : NS_IMETHODIMP
    1945               0 : nsHyperTextAccessible::RemoveSelection(PRInt32 aSelectionNum)
    1946                 : {
    1947               0 :   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
    1948               0 :   NS_ENSURE_STATE(frameSelection);
    1949                 : 
    1950                 :   nsCOMPtr<nsISelection> domSel =
    1951               0 :     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
    1952               0 :   NS_ENSURE_STATE(domSel);
    1953                 : 
    1954                 :   PRInt32 rangeCount;
    1955               0 :   domSel->GetRangeCount(&rangeCount);
    1956               0 :   if (aSelectionNum < 0 || aSelectionNum >= rangeCount)
    1957               0 :     return NS_ERROR_INVALID_ARG;
    1958                 : 
    1959               0 :   nsCOMPtr<nsIDOMRange> range;
    1960               0 :   domSel->GetRangeAt(aSelectionNum, getter_AddRefs(range));
    1961               0 :   return domSel->RemoveRange(range);
    1962                 : }
    1963                 : 
    1964                 : // void nsIAccessibleText::
    1965                 : //   scrollSubstringTo(in long startIndex, in long endIndex,
    1966                 : //                     in unsigned long scrollType);
    1967                 : NS_IMETHODIMP
    1968               0 : nsHyperTextAccessible::ScrollSubstringTo(PRInt32 aStartIndex, PRInt32 aEndIndex,
    1969                 :                                          PRUint32 aScrollType)
    1970                 : {
    1971                 :   PRInt32 startOffset, endOffset;
    1972               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
    1973                 : 
    1974                 :   nsresult rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex,
    1975               0 :                                            getter_AddRefs(startNode),
    1976                 :                                            &startOffset,
    1977               0 :                                            getter_AddRefs(endNode),
    1978               0 :                                            &endOffset);
    1979               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1980                 : 
    1981               0 :   return nsCoreUtils::ScrollSubstringTo(GetFrame(), startNode, startOffset,
    1982               0 :                                         endNode, endOffset, aScrollType);
    1983                 : }
    1984                 : 
    1985                 : // void nsIAccessibleText::
    1986                 : //   scrollSubstringToPoint(in long startIndex, in long endIndex,
    1987                 : //                          in unsigned long coordinateType,
    1988                 : //                          in long x, in long y);
    1989                 : NS_IMETHODIMP
    1990               0 : nsHyperTextAccessible::ScrollSubstringToPoint(PRInt32 aStartIndex,
    1991                 :                                               PRInt32 aEndIndex,
    1992                 :                                               PRUint32 aCoordinateType,
    1993                 :                                               PRInt32 aX, PRInt32 aY)
    1994                 : {
    1995               0 :   nsIFrame *frame = GetFrame();
    1996               0 :   if (!frame)
    1997               0 :     return NS_ERROR_FAILURE;
    1998                 : 
    1999               0 :   nsIntPoint coords;
    2000                 :   nsresult rv = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType,
    2001               0 :                                                   this, &coords);
    2002               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2003                 : 
    2004                 :   PRInt32 startOffset, endOffset;
    2005               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
    2006                 : 
    2007                 :   rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex,
    2008               0 :                                   getter_AddRefs(startNode), &startOffset,
    2009               0 :                                   getter_AddRefs(endNode), &endOffset);
    2010               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2011                 : 
    2012               0 :   nsPresContext *presContext = frame->PresContext();
    2013                 : 
    2014               0 :   bool initialScrolled = false;
    2015               0 :   nsIFrame *parentFrame = frame;
    2016               0 :   while ((parentFrame = parentFrame->GetParent())) {
    2017               0 :     nsIScrollableFrame *scrollableFrame = do_QueryFrame(parentFrame);
    2018               0 :     if (scrollableFrame) {
    2019               0 :       if (!initialScrolled) {
    2020                 :         // Scroll substring to the given point. Turn the point into percents
    2021                 :         // relative scrollable area to use nsCoreUtils::ScrollSubstringTo.
    2022               0 :         nsIntRect frameRect = parentFrame->GetScreenRectExternal();
    2023               0 :         PRInt32 devOffsetX = coords.x - frameRect.x;
    2024               0 :         PRInt32 devOffsetY = coords.y - frameRect.y;
    2025                 : 
    2026                 :         nsPoint offsetPoint(presContext->DevPixelsToAppUnits(devOffsetX),
    2027               0 :                             presContext->DevPixelsToAppUnits(devOffsetY));
    2028                 : 
    2029               0 :         nsSize size(parentFrame->GetSize());
    2030                 : 
    2031                 :         // avoid divide by zero
    2032               0 :         size.width = size.width ? size.width : 1;
    2033               0 :         size.height = size.height ? size.height : 1;
    2034                 : 
    2035               0 :         PRInt16 hPercent = offsetPoint.x * 100 / size.width;
    2036               0 :         PRInt16 vPercent = offsetPoint.y * 100 / size.height;
    2037                 : 
    2038               0 :         rv = nsCoreUtils::ScrollSubstringTo(GetFrame(), startNode, startOffset,
    2039                 :                                             endNode, endOffset,
    2040               0 :                                             vPercent, hPercent);
    2041               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2042                 : 
    2043               0 :         initialScrolled = true;
    2044                 :       } else {
    2045                 :         // Substring was scrolled to the given point already inside its closest
    2046                 :         // scrollable area. If there are nested scrollable areas then make
    2047                 :         // sure we scroll lower areas to the given point inside currently
    2048                 :         // traversed scrollable area.
    2049               0 :         nsCoreUtils::ScrollFrameToPoint(parentFrame, frame, coords);
    2050                 :       }
    2051                 :     }
    2052               0 :     frame = parentFrame;
    2053                 :   }
    2054                 : 
    2055               0 :   return NS_OK;
    2056                 : }
    2057                 : 
    2058                 : ////////////////////////////////////////////////////////////////////////////////
    2059                 : // nsAccessible public
    2060                 : 
    2061                 : nsresult
    2062               0 : nsHyperTextAccessible::GetNameInternal(nsAString& aName)
    2063                 : {
    2064               0 :   nsresult rv = nsAccessibleWrap::GetNameInternal(aName);
    2065               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2066                 : 
    2067                 :   // Get name from title attribute for HTML abbr and acronym elements making it
    2068                 :   // a valid name from markup. Otherwise their name isn't picked up by recursive
    2069                 :   // name computation algorithm. See NS_OK_NAME_FROM_TOOLTIP.
    2070               0 :   if (aName.IsEmpty() && IsAbbreviation()) {
    2071               0 :     nsAutoString name;
    2072               0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, name)) {
    2073               0 :       name.CompressWhitespace();
    2074               0 :       aName = name;
    2075                 :     }
    2076                 :   }
    2077               0 :   return NS_OK;
    2078                 : }
    2079                 : 
    2080                 : void
    2081               0 : nsHyperTextAccessible::InvalidateChildren()
    2082                 : {
    2083               0 :   mOffsets.Clear();
    2084                 : 
    2085               0 :   nsAccessibleWrap::InvalidateChildren();
    2086               0 : }
    2087                 : 
    2088                 : bool
    2089               0 : nsHyperTextAccessible::RemoveChild(nsAccessible* aAccessible)
    2090                 : {
    2091               0 :   PRInt32 childIndex = aAccessible->IndexInParent();
    2092               0 :   PRInt32 count = mOffsets.Length() - childIndex;
    2093               0 :   if (count > 0)
    2094               0 :     mOffsets.RemoveElementsAt(childIndex, count);
    2095                 : 
    2096               0 :   return nsAccessible::RemoveChild(aAccessible);
    2097                 : }
    2098                 : 
    2099                 : ////////////////////////////////////////////////////////////////////////////////
    2100                 : // nsHyperTextAccessible public static
    2101                 : 
    2102               0 : nsresult nsHyperTextAccessible::ContentToRenderedOffset(nsIFrame *aFrame, PRInt32 aContentOffset,
    2103                 :                                                         PRUint32 *aRenderedOffset)
    2104                 : {
    2105               0 :   if (!aFrame) {
    2106                 :     // Current frame not rendered -- this can happen if text is set on
    2107                 :     // something with display: none
    2108               0 :     *aRenderedOffset = 0;
    2109               0 :     return NS_OK;
    2110                 :   }
    2111               0 :   NS_ASSERTION(aFrame->GetType() == nsGkAtoms::textFrame,
    2112                 :                "Need text frame for offset conversion");
    2113               0 :   NS_ASSERTION(aFrame->GetPrevContinuation() == nsnull,
    2114                 :                "Call on primary frame only");
    2115                 : 
    2116               0 :   gfxSkipChars skipChars;
    2117               0 :   gfxSkipCharsIterator iter;
    2118                 :   // Only get info up to original offset, we know that will be larger than skipped offset
    2119               0 :   nsresult rv = aFrame->GetRenderedText(nsnull, &skipChars, &iter, 0, aContentOffset);
    2120               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2121                 : 
    2122               0 :   PRUint32 ourRenderedStart = iter.GetSkippedOffset();
    2123               0 :   PRInt32 ourContentStart = iter.GetOriginalOffset();
    2124                 : 
    2125               0 :   *aRenderedOffset = iter.ConvertOriginalToSkipped(aContentOffset + ourContentStart) -
    2126               0 :                     ourRenderedStart;
    2127                 : 
    2128               0 :   return NS_OK;
    2129                 : }
    2130                 : 
    2131               0 : nsresult nsHyperTextAccessible::RenderedToContentOffset(nsIFrame *aFrame, PRUint32 aRenderedOffset,
    2132                 :                                                         PRInt32 *aContentOffset)
    2133                 : {
    2134               0 :   *aContentOffset = 0;
    2135               0 :   NS_ENSURE_TRUE(aFrame, NS_ERROR_FAILURE);
    2136                 : 
    2137               0 :   NS_ASSERTION(aFrame->GetType() == nsGkAtoms::textFrame,
    2138                 :                "Need text frame for offset conversion");
    2139               0 :   NS_ASSERTION(aFrame->GetPrevContinuation() == nsnull,
    2140                 :                "Call on primary frame only");
    2141                 : 
    2142               0 :   gfxSkipChars skipChars;
    2143               0 :   gfxSkipCharsIterator iter;
    2144                 :   // We only need info up to skipped offset -- that is what we're converting to original offset
    2145               0 :   nsresult rv = aFrame->GetRenderedText(nsnull, &skipChars, &iter, 0, aRenderedOffset);
    2146               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2147                 : 
    2148               0 :   PRUint32 ourRenderedStart = iter.GetSkippedOffset();
    2149               0 :   PRInt32 ourContentStart = iter.GetOriginalOffset();
    2150                 : 
    2151               0 :   *aContentOffset = iter.ConvertSkippedToOriginal(aRenderedOffset + ourRenderedStart) - ourContentStart;
    2152                 : 
    2153               0 :   return NS_OK;
    2154                 : }
    2155                 : 
    2156                 : ////////////////////////////////////////////////////////////////////////////////
    2157                 : // nsHyperTextAccessible public
    2158                 : 
    2159                 : bool
    2160               0 : nsHyperTextAccessible::GetCharAt(PRInt32 aOffset, EGetTextType aShift,
    2161                 :                                  nsAString& aChar, PRInt32* aStartOffset,
    2162                 :                                  PRInt32* aEndOffset)
    2163                 : {
    2164               0 :   aChar.Truncate();
    2165                 : 
    2166               0 :   PRInt32 offset = ConvertMagicOffset(aOffset) + static_cast<PRInt32>(aShift);
    2167               0 :   PRInt32 childIdx = GetChildIndexAtOffset(offset);
    2168               0 :   if (childIdx == -1)
    2169               0 :     return false;
    2170                 : 
    2171               0 :   nsAccessible* child = GetChildAt(childIdx);
    2172               0 :   child->AppendTextTo(aChar, offset - GetChildOffset(childIdx), 1);
    2173                 : 
    2174               0 :   if (aStartOffset)
    2175               0 :     *aStartOffset = offset;
    2176               0 :   if (aEndOffset)
    2177               0 :     *aEndOffset = aChar.IsEmpty() ? offset : offset + 1;
    2178                 : 
    2179               0 :   return true;
    2180                 : }
    2181                 : 
    2182                 : PRInt32
    2183               0 : nsHyperTextAccessible::GetChildOffset(PRUint32 aChildIndex,
    2184                 :                                       bool aInvalidateAfter)
    2185                 : {
    2186               0 :   if (aChildIndex == 0) {
    2187               0 :     if (aInvalidateAfter)
    2188               0 :       mOffsets.Clear();
    2189                 : 
    2190               0 :     return aChildIndex;
    2191                 :   }
    2192                 : 
    2193               0 :   PRInt32 count = mOffsets.Length() - aChildIndex;
    2194               0 :   if (count > 0) {
    2195               0 :     if (aInvalidateAfter)
    2196               0 :       mOffsets.RemoveElementsAt(aChildIndex, count);
    2197                 : 
    2198               0 :     return mOffsets[aChildIndex - 1];
    2199                 :   }
    2200                 : 
    2201               0 :   PRUint32 lastOffset = mOffsets.IsEmpty() ?
    2202               0 :     0 : mOffsets[mOffsets.Length() - 1];
    2203                 : 
    2204               0 :   while (mOffsets.Length() < aChildIndex) {
    2205               0 :     nsAccessible* child = mChildren[mOffsets.Length()];
    2206               0 :     lastOffset += nsAccUtils::TextLength(child);
    2207               0 :     mOffsets.AppendElement(lastOffset);
    2208                 :   }
    2209                 : 
    2210               0 :   return mOffsets[aChildIndex - 1];
    2211                 : }
    2212                 : 
    2213                 : PRInt32
    2214               0 : nsHyperTextAccessible::GetChildIndexAtOffset(PRUint32 aOffset)
    2215                 : {
    2216               0 :   PRUint32 lastOffset = 0;
    2217               0 :   PRUint32 offsetCount = mOffsets.Length();
    2218               0 :   if (offsetCount > 0) {
    2219               0 :     lastOffset = mOffsets[offsetCount - 1];
    2220               0 :     if (aOffset < lastOffset) {
    2221               0 :       PRUint32 low = 0, high = offsetCount;
    2222               0 :       while (high > low) {
    2223               0 :         PRUint32 mid = (high + low) >> 1;
    2224               0 :         if (mOffsets[mid] == aOffset)
    2225               0 :           return mid < offsetCount - 1 ? mid + 1 : mid;
    2226                 : 
    2227               0 :         if (mOffsets[mid] < aOffset)
    2228               0 :           low = mid + 1;
    2229                 :         else
    2230               0 :           high = mid;
    2231                 :       }
    2232               0 :       if (high == offsetCount)
    2233               0 :         return -1;
    2234                 : 
    2235               0 :       return low;
    2236                 :     }
    2237                 :   }
    2238                 : 
    2239               0 :   PRUint32 childCount = GetChildCount();
    2240               0 :   while (mOffsets.Length() < childCount) {
    2241               0 :     nsAccessible* child = GetChildAt(mOffsets.Length());
    2242               0 :     lastOffset += nsAccUtils::TextLength(child);
    2243               0 :     mOffsets.AppendElement(lastOffset);
    2244               0 :     if (aOffset < lastOffset)
    2245               0 :       return mOffsets.Length() - 1;
    2246                 :   }
    2247                 : 
    2248               0 :   if (aOffset == lastOffset)
    2249               0 :     return mOffsets.Length() - 1;
    2250                 : 
    2251               0 :   return -1;
    2252                 : }
    2253                 : 
    2254                 : ////////////////////////////////////////////////////////////////////////////////
    2255                 : // nsHyperTextAccessible protected
    2256                 : 
    2257                 : nsresult
    2258               0 : nsHyperTextAccessible::GetDOMPointByFrameOffset(nsIFrame *aFrame,
    2259                 :                                                 PRInt32 aOffset,
    2260                 :                                                 nsIAccessible *aAccessible,
    2261                 :                                                 nsIDOMNode **aNode,
    2262                 :                                                 PRInt32 *aNodeOffset)
    2263                 : {
    2264               0 :   NS_ENSURE_ARG(aAccessible);
    2265                 : 
    2266               0 :   nsCOMPtr<nsIDOMNode> node;
    2267                 : 
    2268               0 :   if (!aFrame) {
    2269                 :     // If the given frame is null then set offset after the DOM node of the
    2270                 :     // given accessible.
    2271               0 :     nsCOMPtr<nsIDOMNode> DOMNode;
    2272               0 :     aAccessible->GetDOMNode(getter_AddRefs(DOMNode));
    2273               0 :     nsCOMPtr<nsIContent> content(do_QueryInterface(DOMNode));
    2274               0 :     NS_ENSURE_STATE(content);
    2275                 : 
    2276               0 :     nsCOMPtr<nsIContent> parent(content->GetParent());
    2277               0 :     NS_ENSURE_STATE(parent);
    2278                 : 
    2279               0 :     *aNodeOffset = parent->IndexOf(content) + 1;
    2280               0 :     node = do_QueryInterface(parent);
    2281                 : 
    2282               0 :   } else if (aFrame->GetType() == nsGkAtoms::textFrame) {
    2283               0 :     nsCOMPtr<nsIContent> content(aFrame->GetContent());
    2284               0 :     NS_ENSURE_STATE(content);
    2285                 : 
    2286               0 :     nsIFrame *primaryFrame = content->GetPrimaryFrame();
    2287               0 :     nsresult rv = RenderedToContentOffset(primaryFrame, aOffset, aNodeOffset);
    2288               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2289                 : 
    2290               0 :     node = do_QueryInterface(content);
    2291                 : 
    2292                 :   } else {
    2293               0 :     nsCOMPtr<nsIContent> content(aFrame->GetContent());
    2294               0 :     NS_ENSURE_STATE(content);
    2295                 : 
    2296               0 :     nsCOMPtr<nsIContent> parent(content->GetParent());
    2297               0 :     NS_ENSURE_STATE(parent);
    2298                 : 
    2299               0 :     *aNodeOffset = parent->IndexOf(content);
    2300               0 :     node = do_QueryInterface(parent);
    2301                 :   }
    2302                 : 
    2303               0 :   NS_IF_ADDREF(*aNode = node);
    2304               0 :   return NS_OK;
    2305                 : }
    2306                 : 
    2307                 : // nsHyperTextAccessible
    2308                 : nsresult
    2309               0 : nsHyperTextAccessible::RangeBoundToHypertextOffset(nsRange *aRange,
    2310                 :                                                    bool aIsStartBound,
    2311                 :                                                    bool aIsStartHTOffset,
    2312                 :                                                    PRInt32 *aHTOffset)
    2313                 : {
    2314               0 :   nsINode* node = nsnull;
    2315               0 :   PRInt32 nodeOffset = 0;
    2316                 : 
    2317               0 :   if (aIsStartBound) {
    2318               0 :     node = aRange->GetStartParent();
    2319               0 :     nodeOffset = aRange->StartOffset();
    2320                 :   } else {
    2321               0 :     node = aRange->GetEndParent();
    2322               0 :     nodeOffset = aRange->EndOffset();
    2323                 :   }
    2324                 : 
    2325                 :   nsAccessible *startAcc =
    2326               0 :     DOMPointToHypertextOffset(node, nodeOffset, aHTOffset);
    2327                 : 
    2328               0 :   if (aIsStartHTOffset && !startAcc)
    2329               0 :     *aHTOffset = 0;
    2330                 : 
    2331               0 :   return NS_OK;
    2332                 : }
    2333                 : 
    2334                 : // nsHyperTextAccessible
    2335                 : nsresult
    2336               0 : nsHyperTextAccessible::GetSpellTextAttribute(nsINode* aNode,
    2337                 :                                              PRInt32 aNodeOffset,
    2338                 :                                              PRInt32 *aHTStartOffset,
    2339                 :                                              PRInt32 *aHTEndOffset,
    2340                 :                                              nsIPersistentProperties *aAttributes)
    2341                 : {
    2342               0 :   nsTArray<nsRange*> ranges;
    2343               0 :   GetSelectionDOMRanges(nsISelectionController::SELECTION_SPELLCHECK, &ranges);
    2344                 : 
    2345               0 :   PRUint32 rangeCount = ranges.Length();
    2346               0 :   if (!rangeCount)
    2347               0 :     return NS_OK;
    2348                 : 
    2349               0 :   nsCOMPtr<nsIDOMNode> DOMNode = do_QueryInterface(aNode);
    2350               0 :   for (PRUint32 index = 0; index < rangeCount; index++) {
    2351               0 :     nsRange* range = ranges[index];
    2352                 : 
    2353                 :     PRInt16 result;
    2354               0 :     nsresult rv = range->ComparePoint(DOMNode, aNodeOffset, &result);
    2355               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2356                 :     // ComparePoint checks boundary points, but we need to check that
    2357                 :     // text at aNodeOffset is inside the range.
    2358                 :     // See also bug 460690.
    2359               0 :     if (result == 0) {
    2360               0 :       if (aNode == range->GetEndParent() && aNodeOffset == range->EndOffset())
    2361               0 :         result = 1;
    2362                 :     }
    2363                 : 
    2364               0 :     if (result == 1) { // range is before point
    2365               0 :       PRInt32 startHTOffset = 0;
    2366                 :       nsresult rv = RangeBoundToHypertextOffset(range, false, true,
    2367               0 :                                                 &startHTOffset);
    2368               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2369                 : 
    2370               0 :       if (startHTOffset > *aHTStartOffset)
    2371               0 :         *aHTStartOffset = startHTOffset;
    2372                 : 
    2373               0 :     } else if (result == -1) { // range is after point
    2374               0 :       PRInt32 endHTOffset = 0;
    2375                 :       nsresult rv = RangeBoundToHypertextOffset(range, true, false,
    2376               0 :                                                 &endHTOffset);
    2377               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2378                 : 
    2379               0 :       if (endHTOffset < *aHTEndOffset)
    2380               0 :         *aHTEndOffset = endHTOffset;
    2381                 : 
    2382                 :     } else { // point is in range
    2383               0 :       PRInt32 startHTOffset = 0;
    2384                 :       nsresult rv = RangeBoundToHypertextOffset(range, true, true,
    2385               0 :                                                 &startHTOffset);
    2386               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2387                 : 
    2388               0 :       PRInt32 endHTOffset = 0;
    2389                 :       rv = RangeBoundToHypertextOffset(range, false, false,
    2390               0 :                                        &endHTOffset);
    2391               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2392                 : 
    2393               0 :       if (startHTOffset > *aHTStartOffset)
    2394               0 :         *aHTStartOffset = startHTOffset;
    2395               0 :       if (endHTOffset < *aHTEndOffset)
    2396               0 :         *aHTEndOffset = endHTOffset;
    2397                 : 
    2398               0 :       if (aAttributes) {
    2399                 :         nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::invalid,
    2400               0 :                                NS_LITERAL_STRING("spelling"));
    2401                 :       }
    2402                 : 
    2403               0 :       return NS_OK;
    2404                 :     }
    2405                 :   }
    2406                 : 
    2407               0 :   return NS_OK;
    2408                 : }

Generated by: LCOV version 1.7