LCOV - app.info - editor/txtsvc/src/nsTextServicesDocument.cpp

LCOV - code coverage report
| Current view: | directory - editor/txtsvc/src - nsTextServicesDocument.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1399 | 5 | 0.4 %
| Date: | 2012-06-02 | Functions: | 79 | 3 | 3.8 %

           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 Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
          24                 :  *   Neil Deakin <neil@mozdevgroup.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 "mozilla/Util.h"
          41                 :
          42                 : #include "nscore.h"
          43                 : #include "nsLayoutCID.h"
          44                 : #include "nsIAtom.h"
          45                 : #include "nsStaticAtom.h"
          46                 : #include "nsString.h"
          47                 : #include "nsIEnumerator.h"
          48                 : #include "nsIContent.h"
          49                 : #include "nsIContentIterator.h"
          50                 : #include "nsIDOMNodeList.h"
          51                 : #include "nsIDOMRange.h"
          52                 : #include "nsContentUtils.h"
          53                 : #include "nsISelection.h"
          54                 : #include "nsIPlaintextEditor.h"
          55                 : #include "nsTextServicesDocument.h"
          56                 : #include "nsFilteredContentIterator.h"
          57                 :
          58                 : #include "nsIDOMElement.h"
          59                 : #include "nsIDOMHTMLElement.h"
          60                 : #include "nsIDOMHTMLDocument.h"
          61                 :
          62                 : #include "nsLWBrkCIID.h"
          63                 : #include "nsIWordBreaker.h"
          64                 : #include "nsIServiceManager.h"
          65                 :
          66                 : #define LOCK_DOC(doc)
          67                 : #define UNLOCK_DOC(doc)
          68                 :
          69                 : using namespace mozilla;
          70                 :
          71                 : class OffsetEntry
          72                 : {
          73                 : public:
          74               0 :   OffsetEntry(nsIDOMNode *aNode, PRInt32 aOffset, PRInt32 aLength)
          75                 :     : mNode(aNode), mNodeOffset(0), mStrOffset(aOffset), mLength(aLength),
          76               0 :       mIsInsertedText(false), mIsValid(true)
          77                 :   {
          78               0 :     if (mStrOffset < 1)
          79               0 :       mStrOffset = 0;
          80                 :
          81               0 :     if (mLength < 1)
          82               0 :       mLength = 0;
          83               0 :   }
          84                 :
          85               0 :   virtual ~OffsetEntry()
          86               0 :   {
          87               0 :     mNode       = 0;
          88               0 :     mNodeOffset = 0;
          89               0 :     mStrOffset  = 0;
          90               0 :     mLength     = 0;
          91               0 :     mIsValid    = false;
          92               0 :   }
          93                 :
          94                 :   nsIDOMNode *mNode;
          95                 :   PRInt32 mNodeOffset;
          96                 :   PRInt32 mStrOffset;
          97                 :   PRInt32 mLength;
          98                 :   bool    mIsInsertedText;
          99                 :   bool    mIsValid;
         100                 : };
         101                 :
         102                 : #define TS_ATOM(name_, value_) nsIAtom* nsTextServicesDocument::name_ = 0;
         103                 : #include "nsTSAtomList.h"
         104                 : #undef TS_ATOM
         105                 :
         106               0 : nsTextServicesDocument::nsTextServicesDocument()
         107                 : {
         108               0 :   mRefCnt         = 0;
         109                 :
         110               0 :   mSelStartIndex  = -1;
         111               0 :   mSelStartOffset = -1;
         112               0 :   mSelEndIndex    = -1;
         113               0 :   mSelEndOffset   = -1;
         114                 :
         115               0 :   mIteratorStatus = eIsDone;
         116               0 : }
         117                 :
         118               0 : nsTextServicesDocument::~nsTextServicesDocument()
         119                 : {
         120               0 :   ClearOffsetTable(&mOffsetTable);
         121               0 : }
         122                 :
         123                 : #define TS_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_##_buffer, value_)
         124                 : #include "nsTSAtomList.h"
         125                 : #undef TS_ATOM
         126                 :
         127                 : /* static */
         128                 : void
         129            1404 : nsTextServicesDocument::RegisterAtoms()
         130                 : {
         131                 :   static const nsStaticAtom ts_atoms[] = {
         132                 : #define TS_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &name_),
         133                 : #include "nsTSAtomList.h"
         134                 : #undef TS_ATOM
         135                 :   };
         136                 :
         137            1404 :   NS_RegisterStaticAtoms(ts_atoms);
         138            1404 : }
         139                 :
         140               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTextServicesDocument)
         141               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTextServicesDocument)
         142                 :
         143               0 : NS_INTERFACE_MAP_BEGIN(nsTextServicesDocument)
         144               0 :   NS_INTERFACE_MAP_ENTRY(nsITextServicesDocument)
         145               0 :   NS_INTERFACE_MAP_ENTRY(nsIEditActionListener)
         146               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITextServicesDocument)
         147               0 :   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsTextServicesDocument)
         148               0 : NS_INTERFACE_MAP_END
         149                 :
         150            1464 : NS_IMPL_CYCLE_COLLECTION_7(nsTextServicesDocument,
         151                 :                            mDOMDocument,
         152                 :                            mSelCon,
         153                 :                            mIterator,
         154                 :                            mPrevTextBlock,
         155                 :                            mNextTextBlock,
         156                 :                            mExtent,
         157                 :                            mTxtSvcFilter)
         158                 :
         159                 : NS_IMETHODIMP
         160               0 : nsTextServicesDocument::InitWithEditor(nsIEditor *aEditor)
         161                 : {
         162               0 :   nsresult result = NS_OK;
         163               0 :   nsCOMPtr<nsISelectionController> selCon;
         164               0 :   nsCOMPtr<nsIDOMDocument> doc;
         165                 :
         166               0 :   NS_ENSURE_TRUE(aEditor, NS_ERROR_NULL_POINTER);
         167                 :
         168                 :   LOCK_DOC(this);
         169                 :
         170                 :   // Check to see if we already have an mSelCon. If we do, it
         171                 :   // better be the same one the editor uses!
         172                 :
         173               0 :   result = aEditor->GetSelectionController(getter_AddRefs(selCon));
         174                 :
         175               0 :   if (NS_FAILED(result))
         176                 :   {
         177                 :     UNLOCK_DOC(this);
         178               0 :     return result;
         179                 :   }
         180                 :
         181               0 :   if (!selCon || (mSelCon && selCon != mSelCon))
         182                 :   {
         183                 :     UNLOCK_DOC(this);
         184               0 :     return NS_ERROR_FAILURE;
         185                 :   }
         186                 :
         187               0 :   if (!mSelCon)
         188               0 :     mSelCon = selCon;
         189                 :
         190                 :   // Check to see if we already have an mDOMDocument. If we do, it
         191                 :   // better be the same one the editor uses!
         192                 :
         193               0 :   result = aEditor->GetDocument(getter_AddRefs(doc));
         194                 :
         195               0 :   if (NS_FAILED(result))
         196                 :   {
         197                 :     UNLOCK_DOC(this);
         198               0 :     return result;
         199                 :   }
         200                 :
         201               0 :   if (!doc || (mDOMDocument && doc != mDOMDocument))
         202                 :   {
         203                 :     UNLOCK_DOC(this);
         204               0 :     return NS_ERROR_FAILURE;
         205                 :   }
         206                 :
         207               0 :   if (!mDOMDocument)
         208                 :   {
         209               0 :     mDOMDocument = doc;
         210                 :
         211               0 :     result = CreateDocumentContentIterator(getter_AddRefs(mIterator));
         212                 :
         213               0 :     if (NS_FAILED(result))
         214                 :     {
         215                 :       UNLOCK_DOC(this);
         216               0 :       return result;
         217                 :     }
         218                 :
         219               0 :     mIteratorStatus = nsTextServicesDocument::eIsDone;
         220                 :
         221               0 :     result = FirstBlock();
         222                 :
         223               0 :     if (NS_FAILED(result))
         224                 :     {
         225                 :       UNLOCK_DOC(this);
         226               0 :       return result;
         227                 :     }
         228                 :   }
         229                 :
         230               0 :   mEditor = do_GetWeakReference(aEditor);
         231                 :
         232               0 :   result = aEditor->AddEditActionListener(this);
         233                 :
         234                 :   UNLOCK_DOC(this);
         235                 :
         236               0 :   return result;
         237                 : }
         238                 :
         239                 : NS_IMETHODIMP
         240               0 : nsTextServicesDocument::GetDocument(nsIDOMDocument **aDoc)
         241                 : {
         242               0 :   NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
         243                 :
         244               0 :   *aDoc = nsnull; // init out param
         245               0 :   NS_ENSURE_TRUE(mDOMDocument, NS_ERROR_NOT_INITIALIZED);
         246                 :
         247               0 :   *aDoc = mDOMDocument;
         248               0 :   NS_ADDREF(*aDoc);
         249                 :
         250               0 :   return NS_OK;
         251                 : }
         252                 :
         253                 : NS_IMETHODIMP
         254               0 : nsTextServicesDocument::SetExtent(nsIDOMRange* aDOMRange)
         255                 : {
         256               0 :   NS_ENSURE_ARG_POINTER(aDOMRange);
         257               0 :   NS_ENSURE_TRUE(mDOMDocument, NS_ERROR_FAILURE);
         258                 :
         259                 :   LOCK_DOC(this);
         260                 :
         261                 :   // We need to store a copy of aDOMRange since we don't
         262                 :   // know where it came from.
         263                 :
         264               0 :   nsresult result = aDOMRange->CloneRange(getter_AddRefs(mExtent));
         265                 :
         266               0 :   if (NS_FAILED(result))
         267                 :   {
         268                 :     UNLOCK_DOC(this);
         269               0 :     return result;
         270                 :   }
         271                 :
         272                 :   // Create a new iterator based on our new extent range.
         273                 :
         274               0 :   result = CreateContentIterator(mExtent, getter_AddRefs(mIterator));
         275                 :
         276               0 :   if (NS_FAILED(result))
         277                 :   {
         278                 :     UNLOCK_DOC(this);
         279               0 :     return result;
         280                 :   }
         281                 :
         282                 :   // Now position the iterator at the start of the first block
         283                 :   // in the range.
         284                 :
         285               0 :   mIteratorStatus = nsTextServicesDocument::eIsDone;
         286                 :
         287               0 :   result = FirstBlock();
         288                 :
         289                 :   UNLOCK_DOC(this);
         290                 :
         291               0 :   return result;
         292                 : }
         293                 :
         294                 : NS_IMETHODIMP
         295               0 : nsTextServicesDocument::ExpandRangeToWordBoundaries(nsIDOMRange *aRange)
         296                 : {
         297               0 :   NS_ENSURE_ARG_POINTER(aRange);
         298                 :
         299                 :   // Get the end points of the range.
         300                 :
         301               0 :   nsCOMPtr<nsIDOMNode> rngStartNode, rngEndNode;
         302                 :   PRInt32 rngStartOffset, rngEndOffset;
         303                 :
         304                 :   nsresult result =  GetRangeEndPoints(aRange,
         305               0 :                                        getter_AddRefs(rngStartNode),
         306                 :                                        &rngStartOffset,
         307               0 :                                        getter_AddRefs(rngEndNode),
         308               0 :                                        &rngEndOffset);
         309                 :
         310               0 :   NS_ENSURE_SUCCESS(result, result);
         311                 :
         312                 :   // Create a content iterator based on the range.
         313                 :
         314               0 :   nsCOMPtr<nsIContentIterator> iter;
         315               0 :   result = CreateContentIterator(aRange, getter_AddRefs(iter));
         316                 :
         317               0 :   NS_ENSURE_SUCCESS(result, result);
         318                 :
         319                 :   // Find the first text node in the range.
         320                 :
         321                 :   TSDIteratorStatus iterStatus;
         322                 :
         323               0 :   result = FirstTextNode(iter, &iterStatus);
         324               0 :   NS_ENSURE_SUCCESS(result, result);
         325                 :
         326               0 :   if (iterStatus == nsTextServicesDocument::eIsDone)
         327                 :   {
         328                 :     // No text was found so there's no adjustment necessary!
         329               0 :     return NS_OK;
         330                 :   }
         331                 :
         332               0 :   nsINode *firstText = iter->GetCurrentNode();
         333               0 :   NS_ENSURE_TRUE(firstText, NS_ERROR_FAILURE);
         334                 :
         335                 :   // Find the last text node in the range.
         336                 :
         337               0 :   result = LastTextNode(iter, &iterStatus);
         338               0 :   NS_ENSURE_SUCCESS(result, result);
         339                 :
         340               0 :   if (iterStatus == nsTextServicesDocument::eIsDone)
         341                 :   {
         342                 :     // We should never get here because a first text block
         343                 :     // was found above.
         344               0 :     NS_ASSERTION(false, "Found a first without a last!");
         345               0 :     return NS_ERROR_FAILURE;
         346                 :   }
         347                 :
         348               0 :   nsINode *lastText = iter->GetCurrentNode();
         349               0 :   NS_ENSURE_TRUE(lastText, NS_ERROR_FAILURE);
         350                 :
         351                 :   // Now make sure our end points are in terms of text nodes in the range!
         352                 :
         353               0 :   nsCOMPtr<nsIDOMNode> firstTextNode = do_QueryInterface(firstText);
         354               0 :   NS_ENSURE_TRUE(firstTextNode, NS_ERROR_FAILURE);
         355                 :
         356               0 :   if (rngStartNode != firstTextNode)
         357                 :   {
         358                 :     // The range includes the start of the first text node!
         359               0 :     rngStartNode = firstTextNode;
         360               0 :     rngStartOffset = 0;
         361                 :   }
         362                 :
         363               0 :   nsCOMPtr<nsIDOMNode> lastTextNode = do_QueryInterface(lastText);
         364               0 :   NS_ENSURE_TRUE(lastTextNode, NS_ERROR_FAILURE);
         365                 :
         366               0 :   if (rngEndNode != lastTextNode)
         367                 :   {
         368                 :     // The range includes the end of the last text node!
         369               0 :     rngEndNode = lastTextNode;
         370               0 :     nsAutoString str;
         371               0 :     result = lastTextNode->GetNodeValue(str);
         372               0 :     rngEndOffset = str.Length();
         373                 :   }
         374                 :
         375                 :   // Create a doc iterator so that we can scan beyond
         376                 :   // the bounds of the extent range.
         377                 :
         378               0 :   nsCOMPtr<nsIContentIterator> docIter;
         379               0 :   result = CreateDocumentContentIterator(getter_AddRefs(docIter));
         380               0 :   NS_ENSURE_SUCCESS(result, result);
         381                 :
         382                 :   // Grab all the text in the block containing our
         383                 :   // first text node.
         384                 :
         385               0 :   result = docIter->PositionAt(firstText);
         386               0 :   NS_ENSURE_SUCCESS(result, result);
         387                 :
         388               0 :   iterStatus = nsTextServicesDocument::eValid;
         389                 :
         390               0 :   nsTArray<OffsetEntry*> offsetTable;
         391               0 :   nsAutoString blockStr;
         392                 :
         393                 :   result = CreateOffsetTable(&offsetTable, docIter, &iterStatus,
         394               0 :                              nsnull, &blockStr);
         395               0 :   if (NS_FAILED(result))
         396                 :   {
         397               0 :     ClearOffsetTable(&offsetTable);
         398               0 :     return result;
         399                 :   }
         400                 :
         401               0 :   nsCOMPtr<nsIDOMNode> wordStartNode, wordEndNode;
         402                 :   PRInt32 wordStartOffset, wordEndOffset;
         403                 :
         404                 :   result = FindWordBounds(&offsetTable, &blockStr,
         405                 :                           rngStartNode, rngStartOffset,
         406               0 :                           getter_AddRefs(wordStartNode), &wordStartOffset,
         407               0 :                           getter_AddRefs(wordEndNode), &wordEndOffset);
         408                 :
         409               0 :   ClearOffsetTable(&offsetTable);
         410                 :
         411               0 :   NS_ENSURE_SUCCESS(result, result);
         412                 :
         413               0 :   rngStartNode = wordStartNode;
         414               0 :   rngStartOffset = wordStartOffset;
         415                 :
         416                 :   // Grab all the text in the block containing our
         417                 :   // last text node.
         418                 :
         419               0 :   result = docIter->PositionAt(lastText);
         420               0 :   NS_ENSURE_SUCCESS(result, result);
         421                 :
         422               0 :   iterStatus = nsTextServicesDocument::eValid;
         423                 :
         424                 :   result = CreateOffsetTable(&offsetTable, docIter, &iterStatus,
         425               0 :                              nsnull, &blockStr);
         426               0 :   if (NS_FAILED(result))
         427                 :   {
         428               0 :     ClearOffsetTable(&offsetTable);
         429               0 :     return result;
         430                 :   }
         431                 :
         432                 :   result = FindWordBounds(&offsetTable, &blockStr,
         433                 :                           rngEndNode, rngEndOffset,
         434               0 :                           getter_AddRefs(wordStartNode), &wordStartOffset,
         435               0 :                           getter_AddRefs(wordEndNode), &wordEndOffset);
         436                 :
         437               0 :   ClearOffsetTable(&offsetTable);
         438                 :
         439               0 :   NS_ENSURE_SUCCESS(result, result);
         440                 :
         441                 :   // To prevent expanding the range too much, we only change
         442                 :   // rngEndNode and rngEndOffset if it isn't already at the start of the
         443                 :   // word and isn't equivalent to rngStartNode and rngStartOffset.
         444                 :
         445               0 :   if (rngEndNode != wordStartNode || rngEndOffset != wordStartOffset ||
         446               0 :      (rngEndNode == rngStartNode  && rngEndOffset == rngStartOffset))
         447                 :   {
         448               0 :     rngEndNode = wordEndNode;
         449               0 :     rngEndOffset = wordEndOffset;
         450                 :   }
         451                 :
         452                 :   // Now adjust the range so that it uses our new
         453                 :   // end points.
         454                 :
         455               0 :   result = aRange->SetEnd(rngEndNode, rngEndOffset);
         456               0 :   NS_ENSURE_SUCCESS(result, result);
         457                 :
         458               0 :   return aRange->SetStart(rngStartNode, rngStartOffset);
         459                 : }
         460                 :
         461                 : NS_IMETHODIMP
         462               0 : nsTextServicesDocument::SetFilter(nsITextServicesFilter *aFilter)
         463                 : {
         464                 :   // Hang on to the filter so we can set it into the filtered iterator.
         465               0 :   mTxtSvcFilter = aFilter;
         466                 :
         467               0 :   return NS_OK;
         468                 : }
         469                 :
         470                 : NS_IMETHODIMP
         471               0 : nsTextServicesDocument::GetCurrentTextBlock(nsString *aStr)
         472                 : {
         473                 :   nsresult result;
         474                 :
         475               0 :   NS_ENSURE_TRUE(aStr, NS_ERROR_NULL_POINTER);
         476                 :
         477               0 :   aStr->Truncate();
         478                 :
         479               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
         480                 :
         481                 :   LOCK_DOC(this);
         482                 :
         483                 :   result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
         484               0 :                              mExtent, aStr);
         485                 :
         486                 :   UNLOCK_DOC(this);
         487                 :
         488               0 :   return result;
         489                 : }
         490                 :
         491                 : NS_IMETHODIMP
         492               0 : nsTextServicesDocument::FirstBlock()
         493                 : {
         494               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
         495                 :
         496                 :   LOCK_DOC(this);
         497                 :
         498               0 :   nsresult result = FirstTextNode(mIterator, &mIteratorStatus);
         499                 :
         500               0 :   if (NS_FAILED(result))
         501                 :   {
         502                 :     UNLOCK_DOC(this);
         503               0 :     return result;
         504                 :   }
         505                 :
         506                 :   // Keep track of prev and next blocks, just in case
         507                 :   // the text service blows away the current block.
         508                 :
         509               0 :   if (mIteratorStatus == nsTextServicesDocument::eValid)
         510                 :   {
         511               0 :     mPrevTextBlock  = nsnull;
         512               0 :     result = GetFirstTextNodeInNextBlock(getter_AddRefs(mNextTextBlock));
         513                 :   }
         514                 :   else
         515                 :   {
         516                 :     // There's no text block in the document!
         517                 :
         518               0 :     mPrevTextBlock  = nsnull;
         519               0 :     mNextTextBlock  = nsnull;
         520                 :   }
         521                 :
         522                 :   UNLOCK_DOC(this);
         523                 :
         524               0 :   return result;
         525                 : }
         526                 :
         527                 : NS_IMETHODIMP
         528               0 : nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus,
         529                 :                                           PRInt32 *aSelOffset,
         530                 :                                           PRInt32 *aSelLength)
         531                 : {
         532               0 :   nsresult result = NS_OK;
         533                 :
         534               0 :   NS_ENSURE_TRUE(aSelStatus && aSelOffset && aSelLength, NS_ERROR_NULL_POINTER);
         535                 :
         536                 :   LOCK_DOC(this);
         537                 :
         538               0 :   mIteratorStatus = nsTextServicesDocument::eIsDone;
         539                 :
         540               0 :   *aSelStatus = nsITextServicesDocument::eBlockNotFound;
         541               0 :   *aSelOffset = *aSelLength = -1;
         542                 :
         543               0 :   if (!mSelCon || !mIterator)
         544                 :   {
         545                 :     UNLOCK_DOC(this);
         546               0 :     return NS_ERROR_FAILURE;
         547                 :   }
         548                 :
         549               0 :   nsCOMPtr<nsISelection> selection;
         550               0 :   bool isCollapsed = false;
         551                 :
         552               0 :   result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
         553                 :
         554               0 :   if (NS_FAILED(result))
         555                 :   {
         556                 :     UNLOCK_DOC(this);
         557               0 :     return result;
         558                 :   }
         559                 :
         560               0 :   result = selection->GetIsCollapsed(&isCollapsed);
         561                 :
         562               0 :   if (NS_FAILED(result))
         563                 :   {
         564                 :     UNLOCK_DOC(this);
         565               0 :     return result;
         566                 :   }
         567                 :
         568               0 :   nsCOMPtr<nsIContentIterator> iter;
         569               0 :   nsCOMPtr<nsIDOMRange>        range;
         570               0 :   nsCOMPtr<nsIDOMNode>         parent;
         571                 :   PRInt32                      i, rangeCount, offset;
         572                 :
         573               0 :   if (isCollapsed)
         574                 :   {
         575                 :     // We have a caret. Check if the caret is in a text node.
         576                 :     // If it is, make the text node's block the current block.
         577                 :     // If the caret isn't in a text node, search forwards in
         578                 :     // the document, till we find a text node.
         579                 :
         580               0 :     result = selection->GetRangeAt(0, getter_AddRefs(range));
         581                 :
         582               0 :     if (NS_FAILED(result))
         583                 :     {
         584                 :       UNLOCK_DOC(this);
         585               0 :       return result;
         586                 :     }
         587                 :
         588               0 :     if (!range)
         589                 :     {
         590                 :       UNLOCK_DOC(this);
         591               0 :       return NS_ERROR_FAILURE;
         592                 :     }
         593                 :
         594               0 :     result = range->GetStartContainer(getter_AddRefs(parent));
         595                 :
         596               0 :     if (NS_FAILED(result))
         597                 :     {
         598                 :       UNLOCK_DOC(this);
         599               0 :       return result;
         600                 :     }
         601                 :
         602               0 :     if (!parent)
         603                 :     {
         604                 :       UNLOCK_DOC(this);
         605               0 :       return NS_ERROR_FAILURE;
         606                 :     }
         607                 :
         608               0 :     result = range->GetStartOffset(&offset);
         609                 :
         610               0 :     if (NS_FAILED(result))
         611                 :     {
         612                 :       UNLOCK_DOC(this);
         613               0 :       return result;
         614                 :     }
         615                 :
         616               0 :     if (IsTextNode(parent))
         617                 :     {
         618                 :       // The caret is in a text node. Find the beginning
         619                 :       // of the text block containing this text node and
         620                 :       // return.
         621                 :
         622               0 :       nsCOMPtr<nsIContent> content(do_QueryInterface(parent));
         623                 :
         624               0 :       if (!content)
         625                 :       {
         626                 :         UNLOCK_DOC(this);
         627               0 :         return NS_ERROR_FAILURE;
         628                 :       }
         629                 :
         630               0 :       result = mIterator->PositionAt(content);
         631                 :
         632               0 :       if (NS_FAILED(result))
         633                 :       {
         634                 :         UNLOCK_DOC(this);
         635               0 :         return result;
         636                 :       }
         637                 :
         638               0 :       result = FirstTextNodeInCurrentBlock(mIterator);
         639                 :
         640               0 :       if (NS_FAILED(result))
         641                 :       {
         642                 :         UNLOCK_DOC(this);
         643               0 :         return result;
         644                 :       }
         645                 :
         646               0 :       mIteratorStatus = nsTextServicesDocument::eValid;
         647                 :
         648                 :       result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
         649               0 :                                  mExtent, nsnull);
         650                 :
         651               0 :       if (NS_FAILED(result))
         652                 :       {
         653                 :         UNLOCK_DOC(this);
         654               0 :         return result;
         655                 :       }
         656                 :
         657               0 :       result = GetSelection(aSelStatus, aSelOffset, aSelLength);
         658                 :
         659               0 :       if (NS_FAILED(result))
         660                 :       {
         661                 :         UNLOCK_DOC(this);
         662               0 :         return result;
         663                 :       }
         664                 :
         665               0 :       if (*aSelStatus == nsITextServicesDocument::eBlockContains)
         666               0 :         result = SetSelectionInternal(*aSelOffset, *aSelLength, false);
         667                 :     }
         668                 :     else
         669                 :     {
         670                 :       // The caret isn't in a text node. Create an iterator
         671                 :       // based on a range that extends from the current caret
         672                 :       // position to the end of the document, then walk forwards
         673                 :       // till you find a text node, then find the beginning of it's block.
         674                 :
         675               0 :       result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, false, getter_AddRefs(range));
         676                 :
         677               0 :       if (NS_FAILED(result))
         678                 :       {
         679                 :         UNLOCK_DOC(this);
         680               0 :         return result;
         681                 :       }
         682                 :
         683               0 :       result = range->GetCollapsed(&isCollapsed);
         684                 :
         685               0 :       if (NS_FAILED(result))
         686                 :       {
         687                 :         UNLOCK_DOC(this);
         688               0 :         return result;
         689                 :       }
         690                 :
         691               0 :       if (isCollapsed)
         692                 :       {
         693                 :         // If we get here, the range is collapsed because there is nothing after
         694                 :         // the caret! Just return NS_OK;
         695                 :
         696                 :         UNLOCK_DOC(this);
         697               0 :         return NS_OK;
         698                 :       }
         699                 :
         700               0 :       result = CreateContentIterator(range, getter_AddRefs(iter));
         701                 :
         702               0 :       if (NS_FAILED(result))
         703                 :       {
         704                 :         UNLOCK_DOC(this);
         705               0 :         return result;
         706                 :       }
         707                 :
         708               0 :       iter->First();
         709                 :
         710               0 :       nsCOMPtr<nsIContent> content;
         711               0 :       while (!iter->IsDone())
         712                 :       {
         713               0 :         content = do_QueryInterface(iter->GetCurrentNode());
         714                 :
         715               0 :         if (IsTextNode(content))
         716               0 :           break;
         717                 :
         718               0 :         content = nsnull;
         719                 :
         720               0 :         iter->Next();
         721                 :       }
         722                 :
         723               0 :       if (!content)
         724                 :       {
         725                 :         UNLOCK_DOC(this);
         726               0 :         return NS_OK;
         727                 :       }
         728                 :
         729               0 :       result = mIterator->PositionAt(content);
         730                 :
         731               0 :       if (NS_FAILED(result))
         732                 :       {
         733                 :         UNLOCK_DOC(this);
         734               0 :         return result;
         735                 :       }
         736                 :
         737               0 :       result = FirstTextNodeInCurrentBlock(mIterator);
         738                 :
         739               0 :       if (NS_FAILED(result))
         740                 :       {
         741                 :         UNLOCK_DOC(this);
         742               0 :         return result;
         743                 :       }
         744                 :
         745               0 :       mIteratorStatus = nsTextServicesDocument::eValid;
         746                 :
         747                 :       result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
         748               0 :                                  mExtent, nsnull);
         749                 :
         750               0 :       if (NS_FAILED(result))
         751                 :       {
         752                 :         UNLOCK_DOC(this);
         753               0 :         return result;
         754                 :       }
         755                 :
         756               0 :       result = GetSelection(aSelStatus, aSelOffset, aSelLength);
         757                 :
         758               0 :       if (NS_FAILED(result))
         759                 :       {
         760                 :         UNLOCK_DOC(this);
         761               0 :         return result;
         762                 :       }
         763                 :     }
         764                 :
         765                 :     UNLOCK_DOC(this);
         766                 :
         767               0 :     return result;
         768                 :   }
         769                 :
         770                 :   // If we get here, we have an uncollapsed selection!
         771                 :   // Look backwards through each range in the selection till you
         772                 :   // find the first text node. If you find one, find the
         773                 :   // beginning of its text block, and make it the current
         774                 :   // block.
         775                 :
         776               0 :   result = selection->GetRangeCount(&rangeCount);
         777                 :
         778               0 :   if (NS_FAILED(result))
         779                 :   {
         780                 :     UNLOCK_DOC(this);
         781               0 :     return result;
         782                 :   }
         783                 :
         784               0 :   NS_ASSERTION(rangeCount > 0, "Unexpected range count!");
         785                 :
         786               0 :   if (rangeCount <= 0)
         787                 :   {
         788                 :     UNLOCK_DOC(this);
         789               0 :     return NS_OK;
         790                 :   }
         791                 :
         792                 :   // XXX: We may need to add some code here to make sure
         793                 :   //      the ranges are sorted in document appearance order!
         794                 :
         795               0 :   for (i = rangeCount - 1; i >= 0; i--)
         796                 :   {
         797                 :     // Get the i'th range from the selection.
         798                 :
         799               0 :     result = selection->GetRangeAt(i, getter_AddRefs(range));
         800                 :
         801               0 :     if (NS_FAILED(result))
         802                 :     {
         803                 :       UNLOCK_DOC(this);
         804               0 :       return result;
         805                 :     }
         806                 :
         807                 :     // Create an iterator for the range.
         808                 :
         809               0 :     result = CreateContentIterator(range, getter_AddRefs(iter));
         810                 :
         811               0 :     if (NS_FAILED(result))
         812                 :     {
         813                 :       UNLOCK_DOC(this);
         814               0 :       return result;
         815                 :     }
         816                 :
         817               0 :     iter->Last();
         818                 :
         819                 :     // Now walk through the range till we find a text node.
         820                 :
         821               0 :     while (!iter->IsDone())
         822                 :     {
         823               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
         824                 :
         825               0 :       if (IsTextNode(content))
         826                 :       {
         827                 :         // We found a text node, so position the document's
         828                 :         // iterator at the beginning of the block, then get
         829                 :         // the selection in terms of the string offset.
         830                 :
         831               0 :         result = mIterator->PositionAt(content);
         832                 :
         833               0 :         if (NS_FAILED(result))
         834                 :         {
         835                 :           UNLOCK_DOC(this);
         836               0 :           return result;
         837                 :         }
         838                 :
         839               0 :         result = FirstTextNodeInCurrentBlock(mIterator);
         840                 :
         841               0 :         if (NS_FAILED(result))
         842                 :         {
         843                 :           UNLOCK_DOC(this);
         844               0 :           return result;
         845                 :         }
         846                 :
         847               0 :         mIteratorStatus = nsTextServicesDocument::eValid;
         848                 :
         849                 :         result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
         850               0 :                                    mExtent, nsnull);
         851                 :
         852               0 :         if (NS_FAILED(result))
         853                 :         {
         854                 :           UNLOCK_DOC(this);
         855               0 :           return result;
         856                 :         }
         857                 :
         858               0 :         result = GetSelection(aSelStatus, aSelOffset, aSelLength);
         859                 :
         860                 :         UNLOCK_DOC(this);
         861                 :
         862               0 :         return result;
         863                 :
         864                 :       }
         865                 :
         866               0 :       iter->Prev();
         867                 :     }
         868                 :   }
         869                 :
         870                 :   // If we get here, we didn't find any text node in the selection!
         871                 :   // Create a range that extends from the end of the selection,
         872                 :   // to the end of the document, then iterate forwards through
         873                 :   // it till you find a text node!
         874                 :
         875               0 :   result = selection->GetRangeAt(rangeCount - 1, getter_AddRefs(range));
         876                 :
         877               0 :   if (NS_FAILED(result))
         878                 :   {
         879                 :     UNLOCK_DOC(this);
         880               0 :     return result;
         881                 :   }
         882                 :
         883               0 :   if (!range)
         884                 :   {
         885                 :     UNLOCK_DOC(this);
         886               0 :     return NS_ERROR_FAILURE;
         887                 :   }
         888                 :
         889               0 :   result = range->GetEndContainer(getter_AddRefs(parent));
         890                 :
         891               0 :   if (NS_FAILED(result))
         892                 :   {
         893                 :     UNLOCK_DOC(this);
         894               0 :     return result;
         895                 :   }
         896                 :
         897               0 :   if (!parent)
         898                 :   {
         899                 :     UNLOCK_DOC(this);
         900               0 :     return NS_ERROR_FAILURE;
         901                 :   }
         902                 :
         903               0 :   result = range->GetEndOffset(&offset);
         904                 :
         905               0 :   if (NS_FAILED(result))
         906                 :   {
         907                 :     UNLOCK_DOC(this);
         908               0 :     return result;
         909                 :   }
         910                 :
         911               0 :   result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, false, getter_AddRefs(range));
         912                 :
         913               0 :   if (NS_FAILED(result))
         914                 :   {
         915                 :     UNLOCK_DOC(this);
         916               0 :     return result;
         917                 :   }
         918                 :
         919               0 :   result = range->GetCollapsed(&isCollapsed);
         920                 :
         921               0 :   if (NS_FAILED(result))
         922                 :   {
         923                 :     UNLOCK_DOC(this);
         924               0 :     return result;
         925                 :   }
         926                 :
         927               0 :   if (isCollapsed)
         928                 :   {
         929                 :     // If we get here, the range is collapsed because there is nothing after
         930                 :     // the current selection! Just return NS_OK;
         931                 :
         932                 :     UNLOCK_DOC(this);
         933               0 :     return NS_OK;
         934                 :   }
         935                 :
         936               0 :   result = CreateContentIterator(range, getter_AddRefs(iter));
         937                 :
         938               0 :   if (NS_FAILED(result))
         939                 :   {
         940                 :     UNLOCK_DOC(this);
         941               0 :     return result;
         942                 :   }
         943                 :
         944               0 :   iter->First();
         945                 :
         946               0 :   while (!iter->IsDone())
         947                 :   {
         948               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
         949                 :
         950               0 :     if (IsTextNode(content))
         951                 :     {
         952                 :       // We found a text node! Adjust the document's iterator to point
         953                 :       // to the beginning of its text block, then get the current selection.
         954                 :
         955               0 :       result = mIterator->PositionAt(content);
         956                 :
         957               0 :       if (NS_FAILED(result))
         958                 :       {
         959                 :         UNLOCK_DOC(this);
         960               0 :         return result;
         961                 :       }
         962                 :
         963               0 :       result = FirstTextNodeInCurrentBlock(mIterator);
         964                 :
         965               0 :       if (NS_FAILED(result))
         966                 :       {
         967                 :         UNLOCK_DOC(this);
         968               0 :         return result;
         969                 :       }
         970                 :
         971                 :
         972               0 :       mIteratorStatus = nsTextServicesDocument::eValid;
         973                 :
         974                 :       result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus,
         975               0 :                                  mExtent, nsnull);
         976                 :
         977               0 :       if (NS_FAILED(result))
         978                 :       {
         979                 :         UNLOCK_DOC(this);
         980               0 :         return result;
         981                 :       }
         982                 :
         983               0 :       result = GetSelection(aSelStatus, aSelOffset, aSelLength);
         984                 :
         985                 :       UNLOCK_DOC(this);
         986                 :
         987               0 :       return result;
         988                 :     }
         989                 :
         990               0 :     iter->Next();
         991                 :   }
         992                 :
         993                 :   // If we get here, we didn't find any block before or inside
         994                 :   // the selection! Just return OK.
         995                 :
         996                 :   UNLOCK_DOC(this);
         997                 :
         998               0 :   return NS_OK;
         999                 : }
        1000                 :
        1001                 : NS_IMETHODIMP
        1002               0 : nsTextServicesDocument::PrevBlock()
        1003                 : {
        1004               0 :   nsresult result = NS_OK;
        1005                 :
        1006               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
        1007                 :
        1008                 :   LOCK_DOC(this);
        1009                 :
        1010               0 :   if (mIteratorStatus == nsTextServicesDocument::eIsDone)
        1011               0 :     return NS_OK;
        1012                 :
        1013               0 :   switch (mIteratorStatus)
        1014                 :   {
        1015                 :     case nsTextServicesDocument::eValid:
        1016                 :     case nsTextServicesDocument::eNext:
        1017                 :
        1018               0 :       result = FirstTextNodeInPrevBlock(mIterator);
        1019                 :
        1020               0 :       if (NS_FAILED(result))
        1021                 :       {
        1022               0 :         mIteratorStatus = nsTextServicesDocument::eIsDone;
        1023                 :         UNLOCK_DOC(this);
        1024               0 :         return result;
        1025                 :       }
        1026                 :
        1027               0 :       if (mIterator->IsDone())
        1028                 :       {
        1029               0 :         mIteratorStatus = nsTextServicesDocument::eIsDone;
        1030                 :         UNLOCK_DOC(this);
        1031               0 :         return NS_OK;
        1032                 :       }
        1033                 :
        1034               0 :       mIteratorStatus = nsTextServicesDocument::eValid;
        1035               0 :       break;
        1036                 :
        1037                 :     case nsTextServicesDocument::ePrev:
        1038                 :
        1039                 :       // The iterator already points to the previous
        1040                 :       // block, so don't do anything.
        1041                 :
        1042               0 :       mIteratorStatus = nsTextServicesDocument::eValid;
        1043               0 :       break;
        1044                 :
        1045                 :     default:
        1046                 :
        1047               0 :       mIteratorStatus = nsTextServicesDocument::eIsDone;
        1048               0 :       break;
        1049                 :   }
        1050                 :
        1051                 :   // Keep track of prev and next blocks, just in case
        1052                 :   // the text service blows away the current block.
        1053                 :
        1054               0 :   if (mIteratorStatus == nsTextServicesDocument::eValid)
        1055                 :   {
        1056               0 :     result = GetFirstTextNodeInPrevBlock(getter_AddRefs(mPrevTextBlock));
        1057               0 :     result = GetFirstTextNodeInNextBlock(getter_AddRefs(mNextTextBlock));
        1058                 :   }
        1059                 :   else
        1060                 :   {
        1061                 :     // We must be done!
        1062                 :
        1063               0 :     mPrevTextBlock = nsnull;
        1064               0 :     mNextTextBlock = nsnull;
        1065                 :   }
        1066                 :
        1067                 :   UNLOCK_DOC(this);
        1068                 :
        1069               0 :   return result;
        1070                 : }
        1071                 :
        1072                 : NS_IMETHODIMP
        1073               0 : nsTextServicesDocument::NextBlock()
        1074                 : {
        1075               0 :   nsresult result = NS_OK;
        1076                 :
        1077               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
        1078                 :
        1079                 :   LOCK_DOC(this);
        1080                 :
        1081               0 :   if (mIteratorStatus == nsTextServicesDocument::eIsDone)
        1082               0 :     return NS_OK;
        1083                 :
        1084               0 :   switch (mIteratorStatus)
        1085                 :   {
        1086                 :     case nsTextServicesDocument::eValid:
        1087                 :
        1088                 :       // Advance the iterator to the next text block.
        1089                 :
        1090               0 :       result = FirstTextNodeInNextBlock(mIterator);
        1091                 :
        1092               0 :       if (NS_FAILED(result))
        1093                 :       {
        1094               0 :         mIteratorStatus = nsTextServicesDocument::eIsDone;
        1095                 :         UNLOCK_DOC(this);
        1096               0 :         return result;
        1097                 :       }
        1098                 :
        1099               0 :       if (mIterator->IsDone())
        1100                 :       {
        1101               0 :         mIteratorStatus = nsTextServicesDocument::eIsDone;
        1102                 :         UNLOCK_DOC(this);
        1103               0 :         return NS_OK;
        1104                 :       }
        1105                 :
        1106               0 :       mIteratorStatus = nsTextServicesDocument::eValid;
        1107               0 :       break;
        1108                 :
        1109                 :     case nsTextServicesDocument::eNext:
        1110                 :
        1111                 :       // The iterator already points to the next block,
        1112                 :       // so don't do anything to it!
        1113                 :
        1114               0 :       mIteratorStatus = nsTextServicesDocument::eValid;
        1115               0 :       break;
        1116                 :
        1117                 :     case nsTextServicesDocument::ePrev:
        1118                 :
        1119                 :       // If the iterator is pointing to the previous block,
        1120                 :       // we know that there is no next text block! Just
        1121                 :       // fall through to the default case!
        1122                 :
        1123                 :     default:
        1124                 :
        1125               0 :       mIteratorStatus = nsTextServicesDocument::eIsDone;
        1126               0 :       break;
        1127                 :   }
        1128                 :
        1129                 :   // Keep track of prev and next blocks, just in case
        1130                 :   // the text service blows away the current block.
        1131                 :
        1132               0 :   if (mIteratorStatus == nsTextServicesDocument::eValid)
        1133                 :   {
        1134               0 :     result = GetFirstTextNodeInPrevBlock(getter_AddRefs(mPrevTextBlock));
        1135               0 :     result = GetFirstTextNodeInNextBlock(getter_AddRefs(mNextTextBlock));
        1136                 :   }
        1137                 :   else
        1138                 :   {
        1139                 :     // We must be done.
        1140                 :
        1141               0 :     mPrevTextBlock = nsnull;
        1142               0 :     mNextTextBlock = nsnull;
        1143                 :   }
        1144                 :
        1145                 :
        1146                 :   UNLOCK_DOC(this);
        1147                 :
        1148               0 :   return result;
        1149                 : }
        1150                 :
        1151                 : NS_IMETHODIMP
        1152               0 : nsTextServicesDocument::IsDone(bool *aIsDone)
        1153                 : {
        1154               0 :   NS_ENSURE_TRUE(aIsDone, NS_ERROR_NULL_POINTER);
        1155                 :
        1156               0 :   *aIsDone = false;
        1157                 :
        1158               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
        1159                 :
        1160                 :   LOCK_DOC(this);
        1161                 :
        1162               0 :   *aIsDone = (mIteratorStatus == nsTextServicesDocument::eIsDone) ? true : false;
        1163                 :
        1164                 :   UNLOCK_DOC(this);
        1165                 :
        1166               0 :   return NS_OK;
        1167                 : }
        1168                 :
        1169                 : NS_IMETHODIMP
        1170               0 : nsTextServicesDocument::SetSelection(PRInt32 aOffset, PRInt32 aLength)
        1171                 : {
        1172                 :   nsresult result;
        1173                 :
        1174               0 :   NS_ENSURE_TRUE(mSelCon && aOffset >= 0 && aLength >= 0, NS_ERROR_FAILURE);
        1175                 :
        1176                 :   LOCK_DOC(this);
        1177                 :
        1178               0 :   result = SetSelectionInternal(aOffset, aLength, true);
        1179                 :
        1180                 :   UNLOCK_DOC(this);
        1181                 :
        1182                 :   //**** KDEBUG ****
        1183                 :   // printf("\n * Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        1184                 :   //**** KDEBUG ****
        1185                 :
        1186               0 :   return result;
        1187                 : }
        1188                 :
        1189                 : NS_IMETHODIMP
        1190               0 : nsTextServicesDocument::ScrollSelectionIntoView()
        1191                 : {
        1192                 :   nsresult result;
        1193                 :
        1194               0 :   NS_ENSURE_TRUE(mSelCon, NS_ERROR_FAILURE);
        1195                 :
        1196                 :   LOCK_DOC(this);
        1197                 :
        1198                 :   // After ScrollSelectionIntoView(), the pending notifications might be flushed
        1199                 :   // and PresShell/PresContext/Frames may be dead. See bug 418470.
        1200               0 :   result = mSelCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION,
        1201               0 :                                             nsISelectionController::SCROLL_SYNCHRONOUS);
        1202                 :
        1203                 :   UNLOCK_DOC(this);
        1204                 :
        1205               0 :   return result;
        1206                 : }
        1207                 :
        1208                 : NS_IMETHODIMP
        1209               0 : nsTextServicesDocument::DeleteSelection()
        1210                 : {
        1211               0 :   nsresult result = NS_OK;
        1212                 :
        1213                 :   // We don't allow deletion during a collapsed selection!
        1214               0 :   nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
        1215               0 :   NS_ASSERTION(editor, "DeleteSelection called without an editor present!");
        1216               0 :   NS_ASSERTION(SelectionIsValid(), "DeleteSelection called without a valid selection!");
        1217                 :
        1218               0 :   if (!editor || !SelectionIsValid())
        1219               0 :     return NS_ERROR_FAILURE;
        1220                 :
        1221               0 :   if (SelectionIsCollapsed())
        1222               0 :     return NS_OK;
        1223                 :
        1224                 :   LOCK_DOC(this);
        1225                 :
        1226                 :   //**** KDEBUG ****
        1227                 :   // printf("\n---- Before Delete\n");
        1228                 :   // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        1229                 :   // PrintOffsetTable();
        1230                 :   //**** KDEBUG ****
        1231                 :
        1232                 :   // If we have an mExtent, save off its current set of
        1233                 :   // end points so we can compare them against mExtent's
        1234                 :   // set after the deletion of the content.
        1235                 :
        1236               0 :   nsCOMPtr<nsIDOMNode> origStartNode, origEndNode;
        1237               0 :   PRInt32 origStartOffset = 0, origEndOffset = 0;
        1238                 :
        1239               0 :   if (mExtent)
        1240                 :   {
        1241                 :     result = GetRangeEndPoints(mExtent,
        1242               0 :                                getter_AddRefs(origStartNode), &origStartOffset,
        1243               0 :                                getter_AddRefs(origEndNode), &origEndOffset);
        1244                 :
        1245               0 :     if (NS_FAILED(result))
        1246                 :     {
        1247                 :       UNLOCK_DOC(this);
        1248               0 :       return result;
        1249                 :     }
        1250                 :   }
        1251                 :
        1252                 :   PRInt32 i, selLength;
        1253                 :   OffsetEntry *entry, *newEntry;
        1254                 :
        1255               0 :   for (i = mSelStartIndex; i <= mSelEndIndex; i++)
        1256                 :   {
        1257               0 :     entry = mOffsetTable[i];
        1258                 :
        1259               0 :     if (i == mSelStartIndex)
        1260                 :     {
        1261                 :       // Calculate the length of the selection. Note that the
        1262                 :       // selection length can be zero if the start of the selection
        1263                 :       // is at the very end of a text node entry.
        1264                 :
        1265               0 :       if (entry->mIsInsertedText)
        1266                 :       {
        1267                 :         // Inserted text offset entries have no width when
        1268                 :         // talking in terms of string offsets! If the beginning
        1269                 :         // of the selection is in an inserted text offset entry,
        1270                 :         // the caret is always at the end of the entry!
        1271                 :
        1272               0 :         selLength = 0;
        1273                 :       }
        1274                 :       else
        1275               0 :         selLength = entry->mLength - (mSelStartOffset - entry->mStrOffset);
        1276                 :
        1277               0 :       if (selLength > 0 && mSelStartOffset > entry->mStrOffset)
        1278                 :       {
        1279                 :         // Selection doesn't start at the beginning of the
        1280                 :         // text node entry. We need to split this entry into
        1281                 :         // two pieces, the piece before the selection, and
        1282                 :         // the piece inside the selection.
        1283                 :
        1284               0 :         result = SplitOffsetEntry(i, selLength);
        1285                 :
        1286               0 :         if (NS_FAILED(result))
        1287                 :         {
        1288                 :           UNLOCK_DOC(this);
        1289               0 :           return result;
        1290                 :         }
        1291                 :
        1292                 :         // Adjust selection indexes to account for new entry:
        1293                 :
        1294               0 :         ++mSelStartIndex;
        1295               0 :         ++mSelEndIndex;
        1296               0 :         ++i;
        1297                 :
        1298               0 :         entry = mOffsetTable[i];
        1299                 :       }
        1300                 :
        1301                 :
        1302               0 :       if (selLength > 0 && mSelStartIndex < mSelEndIndex)
        1303                 :       {
        1304                 :         // The entire entry is contained in the selection. Mark the
        1305                 :         // entry invalid.
        1306                 :
        1307               0 :         entry->mIsValid = false;
        1308                 :       }
        1309                 :     }
        1310                 :
        1311                 :   //**** KDEBUG ****
        1312                 :   // printf("\n---- Middle Delete\n");
        1313                 :   // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        1314                 :   // PrintOffsetTable();
        1315                 :   //**** KDEBUG ****
        1316                 :
        1317               0 :     if (i == mSelEndIndex)
        1318                 :     {
        1319               0 :       if (entry->mIsInsertedText)
        1320                 :       {
        1321                 :         // Inserted text offset entries have no width when
        1322                 :         // talking in terms of string offsets! If the end
        1323                 :         // of the selection is in an inserted text offset entry,
        1324                 :         // the selection includes the entire entry!
        1325                 :
        1326               0 :         entry->mIsValid = false;
        1327                 :       }
        1328                 :       else
        1329                 :       {
        1330                 :         // Calculate the length of the selection. Note that the
        1331                 :         // selection length can be zero if the end of the selection
        1332                 :         // is at the very beginning of a text node entry.
        1333                 :
        1334               0 :         selLength = mSelEndOffset - entry->mStrOffset;
        1335                 :
        1336               0 :         if (selLength > 0 && mSelEndOffset < entry->mStrOffset + entry->mLength)
        1337                 :         {
        1338                 :           // mStrOffset is guaranteed to be inside the selection, even
        1339                 :           // when mSelStartIndex == mSelEndIndex.
        1340                 :
        1341               0 :           result = SplitOffsetEntry(i, entry->mLength - selLength);
        1342                 :
        1343               0 :           if (NS_FAILED(result))
        1344                 :           {
        1345                 :             UNLOCK_DOC(this);
        1346               0 :             return result;
        1347                 :           }
        1348                 :
        1349                 :           // Update the entry fields:
        1350                 :
        1351               0 :           newEntry = mOffsetTable[i+1];
        1352               0 :           newEntry->mNodeOffset = entry->mNodeOffset;
        1353                 :         }
        1354                 :
        1355                 :
        1356               0 :         if (selLength > 0 && mSelEndOffset == entry->mStrOffset + entry->mLength)
        1357                 :         {
        1358                 :           // The entire entry is contained in the selection. Mark the
        1359                 :           // entry invalid.
        1360                 :
        1361               0 :           entry->mIsValid = false;
        1362                 :         }
        1363                 :       }
        1364                 :     }
        1365                 :
        1366               0 :     if (i != mSelStartIndex && i != mSelEndIndex)
        1367                 :     {
        1368                 :       // The entire entry is contained in the selection. Mark the
        1369                 :       // entry invalid.
        1370                 :
        1371               0 :       entry->mIsValid = false;
        1372                 :     }
        1373                 :   }
        1374                 :
        1375                 :   // Make sure mIterator always points to something valid!
        1376                 :
        1377               0 :   AdjustContentIterator();
        1378                 :
        1379                 :   // Now delete the actual content!
        1380                 :
        1381               0 :   result = editor->DeleteSelection(nsIEditor::ePrevious);
        1382                 :
        1383               0 :   if (NS_FAILED(result))
        1384                 :   {
        1385                 :     UNLOCK_DOC(this);
        1386               0 :     return result;
        1387                 :   }
        1388                 :
        1389                 :   // Now that we've actually deleted the selected content,
        1390                 :   // check to see if our mExtent has changed, if so, then
        1391                 :   // we have to create a new content iterator!
        1392                 :
        1393               0 :   if (origStartNode && origEndNode)
        1394                 :   {
        1395               0 :     nsCOMPtr<nsIDOMNode> curStartNode, curEndNode;
        1396               0 :     PRInt32 curStartOffset = 0, curEndOffset = 0;
        1397                 :
        1398                 :     result = GetRangeEndPoints(mExtent,
        1399               0 :                                getter_AddRefs(curStartNode), &curStartOffset,
        1400               0 :                                getter_AddRefs(curEndNode), &curEndOffset);
        1401                 :
        1402               0 :     if (NS_FAILED(result))
        1403                 :     {
        1404                 :       UNLOCK_DOC(this);
        1405               0 :       return result;
        1406                 :     }
        1407                 :
        1408               0 :     if (origStartNode != curStartNode || origEndNode != curEndNode)
        1409                 :     {
        1410                 :       // The range has changed, so we need to create a new content
        1411                 :       // iterator based on the new range.
        1412                 :
        1413               0 :       nsCOMPtr<nsIContent> curContent;
        1414                 :
        1415               0 :       if (mIteratorStatus != nsTextServicesDocument::eIsDone)
        1416                 :       {
        1417                 :         // The old iterator is still pointing to something valid,
        1418                 :         // so get its current node so we can restore it after we
        1419                 :         // create the new iterator!
        1420                 :
        1421               0 :         curContent = do_QueryInterface(mIterator->GetCurrentNode());
        1422                 :       }
        1423                 :
        1424                 :       // Create the new iterator.
        1425                 :
        1426               0 :       result = CreateContentIterator(mExtent, getter_AddRefs(mIterator));
        1427                 :
        1428               0 :       if (NS_FAILED(result))
        1429                 :       {
        1430                 :         UNLOCK_DOC(this);
        1431               0 :         return result;
        1432                 :       }
        1433                 :
        1434                 :       // Now make the new iterator point to the content node
        1435                 :       // the old one was pointing at.
        1436                 :
        1437               0 :       if (curContent)
        1438                 :       {
        1439               0 :         result = mIterator->PositionAt(curContent);
        1440                 :
        1441               0 :         if (NS_FAILED(result))
        1442               0 :           mIteratorStatus = eIsDone;
        1443                 :         else
        1444               0 :           mIteratorStatus = eValid;
        1445                 :       }
        1446                 :     }
        1447                 :   }
        1448                 :
        1449               0 :   entry = 0;
        1450                 :
        1451                 :   // Move the caret to the end of the first valid entry.
        1452                 :   // Start with mSelStartIndex since it may still be valid.
        1453                 :
        1454               0 :   for (i = mSelStartIndex; !entry && i >= 0; i--)
        1455                 :   {
        1456               0 :     entry = mOffsetTable[i];
        1457                 :
        1458               0 :     if (!entry->mIsValid)
        1459               0 :       entry = 0;
        1460                 :     else
        1461                 :     {
        1462               0 :       mSelStartIndex  = mSelEndIndex  = i;
        1463               0 :       mSelStartOffset = mSelEndOffset = entry->mStrOffset + entry->mLength;
        1464                 :     }
        1465                 :   }
        1466                 :
        1467                 :   // If we still don't have a valid entry, move the caret
        1468                 :   // to the next valid entry after the selection:
        1469                 :
        1470               0 :   for (i = mSelEndIndex; !entry && i < PRInt32(mOffsetTable.Length()); i++)
        1471                 :   {
        1472               0 :     entry = mOffsetTable[i];
        1473                 :
        1474               0 :     if (!entry->mIsValid)
        1475               0 :       entry = 0;
        1476                 :     else
        1477                 :     {
        1478               0 :       mSelStartIndex = mSelEndIndex = i;
        1479               0 :       mSelStartOffset = mSelEndOffset = entry->mStrOffset;
        1480                 :     }
        1481                 :   }
        1482                 :
        1483               0 :   if (entry)
        1484               0 :     result = SetSelection(mSelStartOffset, 0);
        1485                 :   else
        1486                 :   {
        1487                 :     // Uuughh we have no valid offset entry to place our
        1488                 :     // caret ... just mark the selection invalid.
        1489                 :
        1490               0 :     mSelStartIndex  = mSelEndIndex  = -1;
        1491               0 :     mSelStartOffset = mSelEndOffset = -1;
        1492                 :   }
        1493                 :
        1494                 :   // Now remove any invalid entries from the offset table.
        1495                 :
        1496               0 :   result = RemoveInvalidOffsetEntries();
        1497                 :
        1498                 :   //**** KDEBUG ****
        1499                 :   // printf("\n---- After Delete\n");
        1500                 :   // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        1501                 :   // PrintOffsetTable();
        1502                 :   //**** KDEBUG ****
        1503                 :
        1504                 :   UNLOCK_DOC(this);
        1505                 :
        1506               0 :   return result;
        1507                 : }
        1508                 :
        1509                 : NS_IMETHODIMP
        1510               0 : nsTextServicesDocument::InsertText(const nsString *aText)
        1511                 : {
        1512               0 :   nsresult result = NS_OK;
        1513                 :
        1514               0 :   nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
        1515               0 :   NS_ASSERTION(editor, "InsertText called without an editor present!");
        1516                 :
        1517               0 :   if (!editor || !SelectionIsValid())
        1518               0 :     return NS_ERROR_FAILURE;
        1519                 :
        1520               0 :   NS_ENSURE_TRUE(aText, NS_ERROR_NULL_POINTER);
        1521                 :
        1522                 :   // If the selection is not collapsed, we need to save
        1523                 :   // off the selection offsets so we can restore the
        1524                 :   // selection and delete the selected content after we've
        1525                 :   // inserted the new text. This is necessary to try and
        1526                 :   // retain as much of the original style of the content
        1527                 :   // being deleted.
        1528                 :
        1529               0 :   bool collapsedSelection = SelectionIsCollapsed();
        1530               0 :   PRInt32 savedSelOffset = mSelStartOffset;
        1531               0 :   PRInt32 savedSelLength = mSelEndOffset - mSelStartOffset;
        1532                 :
        1533               0 :   if (!collapsedSelection)
        1534                 :   {
        1535                 :     // Collapse to the start of the current selection
        1536                 :     // for the insert!
        1537                 :
        1538               0 :     result = SetSelection(mSelStartOffset, 0);
        1539                 :
        1540               0 :     NS_ENSURE_SUCCESS(result, result);
        1541                 :   }
        1542                 :
        1543                 :
        1544                 :   LOCK_DOC(this);
        1545                 :
        1546               0 :   result = editor->BeginTransaction();
        1547                 :
        1548               0 :   if (NS_FAILED(result))
        1549                 :   {
        1550                 :     UNLOCK_DOC(this);
        1551               0 :     return result;
        1552                 :   }
        1553                 :
        1554               0 :   nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(editor, &result));
        1555               0 :   if (textEditor)
        1556               0 :     result = textEditor->InsertText(*aText);
        1557                 :
        1558               0 :   if (NS_FAILED(result))
        1559                 :   {
        1560               0 :     editor->EndTransaction();
        1561                 :     UNLOCK_DOC(this);
        1562               0 :     return result;
        1563                 :   }
        1564                 :
        1565                 :   //**** KDEBUG ****
        1566                 :   // printf("\n---- Before Insert\n");
        1567                 :   // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        1568                 :   // PrintOffsetTable();
        1569                 :   //**** KDEBUG ****
        1570                 :
        1571               0 :   PRInt32 strLength = aText->Length();
        1572                 :   PRUint32 i;
        1573                 :
        1574               0 :   nsCOMPtr<nsISelection> selection;
        1575                 :   OffsetEntry *itEntry;
        1576               0 :   OffsetEntry *entry = mOffsetTable[mSelStartIndex];
        1577               0 :   void *node         = entry->mNode;
        1578                 :
        1579               0 :   NS_ASSERTION((entry->mIsValid), "Invalid insertion point!");
        1580                 :
        1581               0 :   if (entry->mStrOffset == mSelStartOffset)
        1582                 :   {
        1583               0 :     if (entry->mIsInsertedText)
        1584                 :     {
        1585                 :       // If the caret is in an inserted text offset entry,
        1586                 :       // we simply insert the text at the end of the entry.
        1587                 :
        1588               0 :       entry->mLength += strLength;
        1589                 :     }
        1590                 :     else
        1591                 :     {
        1592                 :       // Insert an inserted text offset entry before the current
        1593                 :       // entry!
        1594                 :
        1595               0 :       itEntry = new OffsetEntry(entry->mNode, entry->mStrOffset, strLength);
        1596                 :
        1597               0 :       if (!itEntry)
        1598                 :       {
        1599               0 :         editor->EndTransaction();
        1600                 :         UNLOCK_DOC(this);
        1601               0 :         return NS_ERROR_OUT_OF_MEMORY;
        1602                 :       }
        1603                 :
        1604               0 :       itEntry->mIsInsertedText = true;
        1605               0 :       itEntry->mNodeOffset = entry->mNodeOffset;
        1606                 :
        1607               0 :       if (!mOffsetTable.InsertElementAt(mSelStartIndex, itEntry))
        1608                 :       {
        1609               0 :         editor->EndTransaction();
        1610                 :         UNLOCK_DOC(this);
        1611               0 :         return NS_ERROR_FAILURE;
        1612                 :       }
        1613                 :     }
        1614                 :   }
        1615               0 :   else if ((entry->mStrOffset + entry->mLength) == mSelStartOffset)
        1616                 :   {
        1617                 :     // We are inserting text at the end of the current offset entry.
        1618                 :     // Look at the next valid entry in the table. If it's an inserted
        1619                 :     // text entry, add to its length and adjust its node offset. If
        1620                 :     // it isn't, add a new inserted text entry.
        1621                 :
        1622               0 :     i       = mSelStartIndex + 1;
        1623               0 :     itEntry = 0;
        1624                 :
        1625               0 :     if (mOffsetTable.Length() > i)
        1626                 :     {
        1627               0 :       itEntry = mOffsetTable[i];
        1628                 :
        1629               0 :       if (!itEntry)
        1630                 :       {
        1631               0 :         editor->EndTransaction();
        1632                 :         UNLOCK_DOC(this);
        1633               0 :         return NS_ERROR_FAILURE;
        1634                 :       }
        1635                 :
        1636                 :       // Check if the entry is a match. If it isn't, set
        1637                 :       // iEntry to zero.
        1638                 :
        1639               0 :       if (!itEntry->mIsInsertedText || itEntry->mStrOffset != mSelStartOffset)
        1640               0 :         itEntry = 0;
        1641                 :     }
        1642                 :
        1643               0 :     if (!itEntry)
        1644                 :     {
        1645                 :       // We didn't find an inserted text offset entry, so
        1646                 :       // create one.
        1647                 :
        1648               0 :       itEntry = new OffsetEntry(entry->mNode, mSelStartOffset, 0);
        1649                 :
        1650               0 :       if (!itEntry)
        1651                 :       {
        1652               0 :         editor->EndTransaction();
        1653                 :         UNLOCK_DOC(this);
        1654               0 :         return NS_ERROR_OUT_OF_MEMORY;
        1655                 :       }
        1656                 :
        1657               0 :       itEntry->mNodeOffset = entry->mNodeOffset + entry->mLength;
        1658               0 :       itEntry->mIsInsertedText = true;
        1659                 :
        1660               0 :       if (!mOffsetTable.InsertElementAt(i, itEntry))
        1661                 :       {
        1662               0 :         delete itEntry;
        1663               0 :         return NS_ERROR_FAILURE;
        1664                 :       }
        1665                 :     }
        1666                 :
        1667                 :     // We have a valid inserted text offset entry. Update its
        1668                 :     // length, adjust the selection indexes, and make sure the
        1669                 :     // caret is properly placed!
        1670                 :
        1671               0 :     itEntry->mLength += strLength;
        1672                 :
        1673               0 :     mSelStartIndex = mSelEndIndex = i;
        1674                 :
        1675               0 :     result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
        1676                 :
        1677               0 :     if (NS_FAILED(result))
        1678                 :     {
        1679               0 :       editor->EndTransaction();
        1680                 :       UNLOCK_DOC(this);
        1681               0 :       return result;
        1682                 :     }
        1683                 :
        1684               0 :     result = selection->Collapse(itEntry->mNode, itEntry->mNodeOffset + itEntry->mLength);
        1685                 :
        1686               0 :     if (NS_FAILED(result))
        1687                 :     {
        1688               0 :       editor->EndTransaction();
        1689                 :       UNLOCK_DOC(this);
        1690               0 :       return result;
        1691                 :     }
        1692                 :   }
        1693               0 :   else if ((entry->mStrOffset + entry->mLength) > mSelStartOffset)
        1694                 :   {
        1695                 :     // We are inserting text into the middle of the current offset entry.
        1696                 :     // split the current entry into two parts, then insert an inserted text
        1697                 :     // entry between them!
        1698                 :
        1699               0 :     i = entry->mLength - (mSelStartOffset - entry->mStrOffset);
        1700                 :
        1701               0 :     result = SplitOffsetEntry(mSelStartIndex, i);
        1702                 :
        1703               0 :     if (NS_FAILED(result))
        1704                 :     {
        1705               0 :       editor->EndTransaction();
        1706                 :       UNLOCK_DOC(this);
        1707               0 :       return result;
        1708                 :     }
        1709                 :
        1710               0 :     itEntry = new OffsetEntry(entry->mNode, mSelStartOffset, strLength);
        1711                 :
        1712               0 :     if (!itEntry)
        1713                 :     {
        1714               0 :       editor->EndTransaction();
        1715                 :       UNLOCK_DOC(this);
        1716               0 :       return NS_ERROR_OUT_OF_MEMORY;
        1717                 :     }
        1718                 :
        1719               0 :     itEntry->mIsInsertedText = true;
        1720               0 :     itEntry->mNodeOffset     = entry->mNodeOffset + entry->mLength;
        1721                 :
        1722               0 :     if (!mOffsetTable.InsertElementAt(mSelStartIndex + 1, itEntry))
        1723                 :     {
        1724               0 :       editor->EndTransaction();
        1725                 :       UNLOCK_DOC(this);
        1726               0 :       return NS_ERROR_FAILURE;
        1727                 :     }
        1728                 :
        1729               0 :     mSelEndIndex = ++mSelStartIndex;
        1730                 :   }
        1731                 :
        1732                 :   // We've just finished inserting an inserted text offset entry.
        1733                 :   // update all entries with the same mNode pointer that follow
        1734                 :   // it in the table!
        1735                 :
        1736               0 :   for (i = mSelStartIndex + 1; i < mOffsetTable.Length(); i++)
        1737                 :   {
        1738               0 :     entry = mOffsetTable[i];
        1739                 :
        1740               0 :     if (entry->mNode == node)
        1741                 :     {
        1742               0 :       if (entry->mIsValid)
        1743               0 :         entry->mNodeOffset += strLength;
        1744                 :     }
        1745                 :     else
        1746               0 :       break;
        1747                 :   }
        1748                 :
        1749                 :   //**** KDEBUG ****
        1750                 :   // printf("\n---- After Insert\n");
        1751                 :   // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        1752                 :   // PrintOffsetTable();
        1753                 :   //**** KDEBUG ****
        1754                 :
        1755               0 :   if (!collapsedSelection)
        1756                 :   {
        1757               0 :     result = SetSelection(savedSelOffset, savedSelLength);
        1758                 :
        1759               0 :     if (NS_FAILED(result))
        1760                 :     {
        1761               0 :       editor->EndTransaction();
        1762                 :       UNLOCK_DOC(this);
        1763               0 :       return result;
        1764                 :     }
        1765                 :
        1766               0 :     result = DeleteSelection();
        1767                 :
        1768               0 :     if (NS_FAILED(result))
        1769                 :     {
        1770               0 :       editor->EndTransaction();
        1771                 :       UNLOCK_DOC(this);
        1772               0 :       return result;
        1773                 :     }
        1774                 :   }
        1775                 :
        1776               0 :   result = editor->EndTransaction();
        1777                 :
        1778                 :   UNLOCK_DOC(this);
        1779                 :
        1780               0 :   return result;
        1781                 : }
        1782                 :
        1783                 : NS_IMETHODIMP
        1784               0 : nsTextServicesDocument::DidInsertNode(nsIDOMNode *aNode,
        1785                 :                                       nsIDOMNode *aParent,
        1786                 :                                       PRInt32     aPosition,
        1787                 :                                       nsresult    aResult)
        1788                 : {
        1789               0 :   return NS_OK;
        1790                 : }
        1791                 :
        1792                 : NS_IMETHODIMP
        1793               0 : nsTextServicesDocument::DidDeleteNode(nsIDOMNode *aChild, nsresult aResult)
        1794                 : {
        1795               0 :   NS_ENSURE_SUCCESS(aResult, NS_OK);
        1796                 :
        1797               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
        1798                 :
        1799                 :   //**** KDEBUG ****
        1800                 :   // printf("** DeleteNode: 0x%.8x\n", aChild);
        1801                 :   // fflush(stdout);
        1802                 :   //**** KDEBUG ****
        1803                 :
        1804                 :   LOCK_DOC(this);
        1805                 :
        1806               0 :   PRInt32 nodeIndex = 0;
        1807               0 :   bool hasEntry = false;
        1808                 :   OffsetEntry *entry;
        1809                 :
        1810               0 :   nsresult result = NodeHasOffsetEntry(&mOffsetTable, aChild, &hasEntry, &nodeIndex);
        1811                 :
        1812               0 :   if (NS_FAILED(result))
        1813                 :   {
        1814                 :     UNLOCK_DOC(this);
        1815               0 :     return result;
        1816                 :   }
        1817                 :
        1818               0 :   if (!hasEntry)
        1819                 :   {
        1820                 :     // It's okay if the node isn't in the offset table, the
        1821                 :     // editor could be cleaning house.
        1822                 :
        1823                 :     UNLOCK_DOC(this);
        1824               0 :     return NS_OK;
        1825                 :   }
        1826                 :
        1827               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mIterator->GetCurrentNode());
        1828                 :
        1829               0 :   if (node && node == aChild &&
        1830                 :       mIteratorStatus != nsTextServicesDocument::eIsDone)
        1831                 :   {
        1832                 :     // XXX: This should never really happen because
        1833                 :     // AdjustContentIterator() should have been called prior
        1834                 :     // to the delete to try and position the iterator on the
        1835                 :     // next valid text node in the offset table, and if there
        1836                 :     // wasn't a next, it would've set mIteratorStatus to eIsDone.
        1837                 :
        1838               0 :     NS_ERROR("DeleteNode called for current iterator node.");
        1839                 :   }
        1840                 :
        1841               0 :   PRInt32 tcount = mOffsetTable.Length();
        1842                 :
        1843               0 :   while (nodeIndex < tcount)
        1844                 :   {
        1845               0 :     entry = mOffsetTable[nodeIndex];
        1846                 :
        1847               0 :     if (!entry)
        1848                 :     {
        1849                 :       UNLOCK_DOC(this);
        1850               0 :       return NS_ERROR_FAILURE;
        1851                 :     }
        1852                 :
        1853               0 :     if (entry->mNode == aChild)
        1854                 :     {
        1855               0 :       entry->mIsValid = false;
        1856                 :     }
        1857                 :
        1858               0 :     nodeIndex++;
        1859                 :   }
        1860                 :
        1861                 :   UNLOCK_DOC(this);
        1862                 :
        1863               0 :   return NS_OK;
        1864                 : }
        1865                 :
        1866                 : NS_IMETHODIMP
        1867               0 : nsTextServicesDocument::DidSplitNode(nsIDOMNode *aExistingRightNode,
        1868                 :                                      PRInt32     aOffset,
        1869                 :                                      nsIDOMNode *aNewLeftNode,
        1870                 :                                      nsresult    aResult)
        1871                 : {
        1872                 :   //**** KDEBUG ****
        1873                 :   // printf("** SplitNode: 0x%.8x  %d  0x%.8x\n", aExistingRightNode, aOffset, aNewLeftNode);
        1874                 :   // fflush(stdout);
        1875                 :   //**** KDEBUG ****
        1876               0 :   return NS_OK;
        1877                 : }
        1878                 :
        1879                 : NS_IMETHODIMP
        1880               0 : nsTextServicesDocument::DidJoinNodes(nsIDOMNode  *aLeftNode,
        1881                 :                                      nsIDOMNode  *aRightNode,
        1882                 :                                      nsIDOMNode  *aParent,
        1883                 :                                      nsresult     aResult)
        1884                 : {
        1885               0 :   NS_ENSURE_SUCCESS(aResult, NS_OK);
        1886                 :
        1887                 :   PRInt32 i;
        1888                 :   PRUint16 type;
        1889                 :   nsresult result;
        1890                 :
        1891                 :   //**** KDEBUG ****
        1892                 :   // printf("** JoinNodes: 0x%.8x  0x%.8x  0x%.8x\n", aLeftNode, aRightNode, aParent);
        1893                 :   // fflush(stdout);
        1894                 :   //**** KDEBUG ****
        1895                 :
        1896                 :   // Make sure that both nodes are text nodes!
        1897                 :
        1898               0 :   result = aLeftNode->GetNodeType(&type);
        1899                 :
        1900               0 :   NS_ENSURE_SUCCESS(result, false);
        1901                 :
        1902               0 :   if (nsIDOMNode::TEXT_NODE != type)
        1903                 :   {
        1904               0 :     NS_ERROR("JoinNode called with a non-text left node!");
        1905               0 :     return NS_ERROR_FAILURE;
        1906                 :   }
        1907                 :
        1908               0 :   result = aRightNode->GetNodeType(&type);
        1909                 :
        1910               0 :   NS_ENSURE_SUCCESS(result, false);
        1911                 :
        1912               0 :   if (nsIDOMNode::TEXT_NODE != type)
        1913                 :   {
        1914               0 :     NS_ERROR("JoinNode called with a non-text right node!");
        1915               0 :     return NS_ERROR_FAILURE;
        1916                 :   }
        1917                 :
        1918                 :   // Note: The editor merges the contents of the left node into the
        1919                 :   //       contents of the right.
        1920                 :
        1921               0 :   PRInt32 leftIndex = 0;
        1922               0 :   PRInt32 rightIndex = 0;
        1923               0 :   bool leftHasEntry = false;
        1924               0 :   bool rightHasEntry = false;
        1925                 :
        1926               0 :   result = NodeHasOffsetEntry(&mOffsetTable, aLeftNode, &leftHasEntry, &leftIndex);
        1927                 :
        1928               0 :   NS_ENSURE_SUCCESS(result, result);
        1929                 :
        1930               0 :   if (!leftHasEntry)
        1931                 :   {
        1932                 :     // It's okay if the node isn't in the offset table, the
        1933                 :     // editor could be cleaning house.
        1934               0 :     return NS_OK;
        1935                 :   }
        1936                 :
        1937               0 :   result = NodeHasOffsetEntry(&mOffsetTable, aRightNode, &rightHasEntry, &rightIndex);
        1938                 :
        1939               0 :   NS_ENSURE_SUCCESS(result, result);
        1940                 :
        1941               0 :   if (!rightHasEntry)
        1942                 :   {
        1943                 :     // It's okay if the node isn't in the offset table, the
        1944                 :     // editor could be cleaning house.
        1945               0 :     return NS_OK;
        1946                 :   }
        1947                 :
        1948               0 :   NS_ASSERTION(leftIndex < rightIndex, "Indexes out of order.");
        1949                 :
        1950               0 :   if (leftIndex > rightIndex)
        1951                 :   {
        1952                 :     // Don't know how to handle this situation.
        1953               0 :     return NS_ERROR_FAILURE;
        1954                 :   }
        1955                 :
        1956                 :   LOCK_DOC(this);
        1957                 :
        1958               0 :   OffsetEntry *entry = mOffsetTable[rightIndex];
        1959               0 :   NS_ASSERTION(entry->mNodeOffset == 0, "Unexpected offset value for rightIndex.");
        1960                 :
        1961                 :   // Run through the table and change all entries referring to
        1962                 :   // the left node so that they now refer to the right node:
        1963                 :
        1964               0 :   nsAutoString str;
        1965               0 :   result = aLeftNode->GetNodeValue(str);
        1966               0 :   PRInt32 nodeLength = str.Length();
        1967                 :
        1968               0 :   for (i = leftIndex; i < rightIndex; i++)
        1969                 :   {
        1970               0 :     entry = mOffsetTable[i];
        1971                 :
        1972               0 :     if (entry->mNode == aLeftNode)
        1973                 :     {
        1974               0 :       if (entry->mIsValid)
        1975               0 :         entry->mNode = aRightNode;
        1976                 :     }
        1977                 :     else
        1978               0 :       break;
        1979                 :   }
        1980                 :
        1981                 :   // Run through the table and adjust the node offsets
        1982                 :   // for all entries referring to the right node.
        1983                 :
        1984               0 :   for (i = rightIndex; i < PRInt32(mOffsetTable.Length()); i++)
        1985                 :   {
        1986               0 :     entry = mOffsetTable[i];
        1987                 :
        1988               0 :     if (entry->mNode == aRightNode)
        1989                 :     {
        1990               0 :       if (entry->mIsValid)
        1991               0 :         entry->mNodeOffset += nodeLength;
        1992                 :     }
        1993                 :     else
        1994               0 :       break;
        1995                 :   }
        1996                 :
        1997                 :   // Now check to see if the iterator is pointing to the
        1998                 :   // left node. If it is, make it point to the right node!
        1999                 :
        2000               0 :   nsCOMPtr<nsIContent> leftContent = do_QueryInterface(aLeftNode);
        2001               0 :   nsCOMPtr<nsIContent> rightContent = do_QueryInterface(aRightNode);
        2002                 :
        2003               0 :   if (!leftContent || !rightContent)
        2004                 :   {
        2005                 :     UNLOCK_DOC(this);
        2006               0 :     return NS_ERROR_FAILURE;
        2007                 :   }
        2008                 :
        2009               0 :   if (mIterator->GetCurrentNode() == leftContent)
        2010               0 :     result = mIterator->PositionAt(rightContent);
        2011                 :
        2012                 :   UNLOCK_DOC(this);
        2013                 :
        2014               0 :   return NS_OK;
        2015                 : }
        2016                 :
        2017                 : nsresult
        2018               0 : nsTextServicesDocument::CreateContentIterator(nsIDOMRange *aRange, nsIContentIterator **aIterator)
        2019                 : {
        2020                 :   nsresult result;
        2021                 :
        2022               0 :   NS_ENSURE_TRUE(aRange && aIterator, NS_ERROR_NULL_POINTER);
        2023                 :
        2024               0 :   *aIterator = 0;
        2025                 :
        2026                 :   // Create a nsFilteredContentIterator
        2027                 :   // This class wraps the ContentIterator in order to give itself a chance
        2028                 :   // to filter out certain content nodes
        2029               0 :   nsFilteredContentIterator* filter = new nsFilteredContentIterator(mTxtSvcFilter);
        2030               0 :   *aIterator = static_cast<nsIContentIterator *>(filter);
        2031               0 :   if (*aIterator) {
        2032               0 :     NS_IF_ADDREF(*aIterator);
        2033               0 :     result = filter ? NS_OK : NS_ERROR_FAILURE;
        2034                 :   } else {
        2035               0 :     delete filter;
        2036               0 :     result = NS_ERROR_FAILURE;
        2037                 :   }
        2038               0 :   NS_ENSURE_SUCCESS(result, result);
        2039                 :
        2040               0 :   NS_ENSURE_TRUE(*aIterator, NS_ERROR_NULL_POINTER);
        2041                 :
        2042               0 :   result = (*aIterator)->Init(aRange);
        2043                 :
        2044               0 :   if (NS_FAILED(result))
        2045                 :   {
        2046               0 :     NS_RELEASE((*aIterator));
        2047               0 :     *aIterator = 0;
        2048               0 :     return result;
        2049                 :   }
        2050                 :
        2051               0 :   return NS_OK;
        2052                 : }
        2053                 :
        2054                 : nsresult
        2055               0 : nsTextServicesDocument::GetDocumentContentRootNode(nsIDOMNode **aNode)
        2056                 : {
        2057                 :   nsresult result;
        2058                 :
        2059               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
        2060                 :
        2061               0 :   *aNode = 0;
        2062                 :
        2063               0 :   NS_ENSURE_TRUE(mDOMDocument, NS_ERROR_FAILURE);
        2064                 :
        2065               0 :   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDOMDocument);
        2066                 :
        2067               0 :   if (htmlDoc)
        2068                 :   {
        2069                 :     // For HTML documents, the content root node is the body.
        2070                 :
        2071               0 :     nsCOMPtr<nsIDOMHTMLElement> bodyElement;
        2072                 :
        2073               0 :     result = htmlDoc->GetBody(getter_AddRefs(bodyElement));
        2074                 :
        2075               0 :     NS_ENSURE_SUCCESS(result, result);
        2076                 :
        2077               0 :     NS_ENSURE_TRUE(bodyElement, NS_ERROR_FAILURE);
        2078                 :
        2079               0 :     result = bodyElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode);
        2080                 :   }
        2081                 :   else
        2082                 :   {
        2083                 :     // For non-HTML documents, the content root node will be the document element.
        2084                 :
        2085               0 :     nsCOMPtr<nsIDOMElement> docElement;
        2086                 :
        2087               0 :     result = mDOMDocument->GetDocumentElement(getter_AddRefs(docElement));
        2088                 :
        2089               0 :     NS_ENSURE_SUCCESS(result, result);
        2090                 :
        2091               0 :     NS_ENSURE_TRUE(docElement, NS_ERROR_FAILURE);
        2092                 :
        2093               0 :     result = docElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode);
        2094                 :   }
        2095                 :
        2096               0 :   return result;
        2097                 : }
        2098                 :
        2099                 : nsresult
        2100               0 : nsTextServicesDocument::CreateDocumentContentRange(nsIDOMRange **aRange)
        2101                 : {
        2102               0 :   *aRange = NULL;
        2103                 :
        2104               0 :   nsCOMPtr<nsIDOMNode> node;
        2105               0 :   nsresult rv = GetDocumentContentRootNode(getter_AddRefs(node));
        2106               0 :   NS_ENSURE_SUCCESS(rv, rv);
        2107               0 :   NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER);
        2108                 :
        2109               0 :   nsRefPtr<nsRange> range = new nsRange();
        2110                 :
        2111               0 :   rv = range->SelectNodeContents(node);
        2112               0 :   NS_ENSURE_SUCCESS(rv, rv);
        2113                 :
        2114               0 :   range.forget(aRange);
        2115               0 :   return NS_OK;
        2116                 : }
        2117                 :
        2118                 : nsresult
        2119               0 : nsTextServicesDocument::CreateDocumentContentRootToNodeOffsetRange(nsIDOMNode *aParent, PRInt32 aOffset, bool aToStart, nsIDOMRange **aRange)
        2120                 : {
        2121               0 :   NS_ENSURE_TRUE(aParent && aRange, NS_ERROR_NULL_POINTER);
        2122                 :
        2123               0 :   *aRange = 0;
        2124                 :
        2125               0 :   NS_ASSERTION(aOffset >= 0, "Invalid offset!");
        2126                 :
        2127               0 :   if (aOffset < 0)
        2128               0 :     return NS_ERROR_FAILURE;
        2129                 :
        2130               0 :   nsCOMPtr<nsIDOMNode> bodyNode;
        2131               0 :   nsresult rv = GetDocumentContentRootNode(getter_AddRefs(bodyNode));
        2132               0 :   NS_ENSURE_SUCCESS(rv, rv);
        2133               0 :   NS_ENSURE_TRUE(bodyNode, NS_ERROR_NULL_POINTER);
        2134                 :
        2135               0 :   nsCOMPtr<nsIDOMNode> startNode;
        2136               0 :   nsCOMPtr<nsIDOMNode> endNode;
        2137                 :   PRInt32 startOffset, endOffset;
        2138                 :
        2139               0 :   if (aToStart) {
        2140                 :     // The range should begin at the start of the document
        2141                 :     // and extend up until (aParent, aOffset).
        2142                 :
        2143               0 :     startNode   = bodyNode;
        2144               0 :     startOffset = 0;
        2145               0 :     endNode     = aParent;
        2146               0 :     endOffset   = aOffset;
        2147                 :   } else {
        2148                 :     // The range should begin at (aParent, aOffset) and
        2149                 :     // extend to the end of the document.
        2150                 :
        2151               0 :     nsCOMPtr<nsIDOMNodeList> nodeList;
        2152                 :     PRUint32 nodeListLength;
        2153                 :
        2154               0 :     startNode   = aParent;
        2155               0 :     startOffset = aOffset;
        2156               0 :     endNode     = bodyNode;
        2157               0 :     endOffset   = 0;
        2158                 :
        2159               0 :     rv = bodyNode->GetChildNodes(getter_AddRefs(nodeList));
        2160               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
        2161                 :
        2162               0 :     if (nodeList) {
        2163               0 :       rv = nodeList->GetLength(&nodeListLength);
        2164               0 :       NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
        2165                 :
        2166               0 :       endOffset = (PRInt32)nodeListLength;
        2167                 :     }
        2168                 :   }
        2169                 :
        2170                 :   return nsRange::CreateRange(startNode, startOffset, endNode, endOffset,
        2171               0 :                               aRange);
        2172                 : }
        2173                 :
        2174                 : nsresult
        2175               0 : nsTextServicesDocument::CreateDocumentContentIterator(nsIContentIterator **aIterator)
        2176                 : {
        2177                 :   nsresult result;
        2178                 :
        2179               0 :   NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
        2180                 :
        2181               0 :   nsCOMPtr<nsIDOMRange> range;
        2182                 :
        2183               0 :   result = CreateDocumentContentRange(getter_AddRefs(range));
        2184                 :
        2185               0 :   NS_ENSURE_SUCCESS(result, result);
        2186                 :
        2187               0 :   result = CreateContentIterator(range, aIterator);
        2188                 :
        2189               0 :   return result;
        2190                 : }
        2191                 :
        2192                 : nsresult
        2193               0 : nsTextServicesDocument::AdjustContentIterator()
        2194                 : {
        2195               0 :   nsresult result = NS_OK;
        2196                 :
        2197               0 :   NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
        2198                 :
        2199               0 :   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mIterator->GetCurrentNode()));
        2200                 :
        2201               0 :   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
        2202                 :
        2203               0 :   nsIDOMNode *nodePtr = node.get();
        2204               0 :   PRInt32 tcount      = mOffsetTable.Length();
        2205                 :
        2206               0 :   nsIDOMNode *prevValidNode = 0;
        2207               0 :   nsIDOMNode *nextValidNode = 0;
        2208               0 :   bool foundEntry = false;
        2209                 :   OffsetEntry *entry;
        2210                 :
        2211               0 :   for (PRInt32 i = 0; i < tcount && !nextValidNode; i++)
        2212                 :   {
        2213               0 :     entry = mOffsetTable[i];
        2214                 :
        2215               0 :     NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
        2216                 :
        2217               0 :     if (entry->mNode == nodePtr)
        2218                 :     {
        2219               0 :       if (entry->mIsValid)
        2220                 :       {
        2221                 :         // The iterator is still pointing to something valid!
        2222                 :         // Do nothing!
        2223                 :
        2224               0 :         return NS_OK;
        2225                 :       }
        2226                 :       else
        2227                 :       {
        2228                 :         // We found an invalid entry that points to
        2229                 :         // the current iterator node. Stop looking for
        2230                 :         // a previous valid node!
        2231                 :
        2232               0 :         foundEntry = true;
        2233                 :       }
        2234                 :     }
        2235                 :
        2236               0 :     if (entry->mIsValid)
        2237                 :     {
        2238               0 :       if (!foundEntry)
        2239               0 :         prevValidNode = entry->mNode;
        2240                 :       else
        2241               0 :         nextValidNode = entry->mNode;
        2242                 :     }
        2243                 :   }
        2244                 :
        2245               0 :   nsCOMPtr<nsIContent> content;
        2246                 :
        2247               0 :   if (prevValidNode)
        2248               0 :     content = do_QueryInterface(prevValidNode);
        2249               0 :   else if (nextValidNode)
        2250               0 :     content = do_QueryInterface(nextValidNode);
        2251                 :
        2252               0 :   if (content)
        2253                 :   {
        2254               0 :     result = mIterator->PositionAt(content);
        2255                 :
        2256               0 :     if (NS_FAILED(result))
        2257               0 :       mIteratorStatus = eIsDone;
        2258                 :     else
        2259               0 :       mIteratorStatus = eValid;
        2260                 :
        2261               0 :     return result;
        2262                 :   }
        2263                 :
        2264                 :   // If we get here, there aren't any valid entries
        2265                 :   // in the offset table! Try to position the iterator
        2266                 :   // on the next text block first, then previous if
        2267                 :   // one doesn't exist!
        2268                 :
        2269               0 :   if (mNextTextBlock)
        2270                 :   {
        2271               0 :     result = mIterator->PositionAt(mNextTextBlock);
        2272                 :
        2273               0 :     if (NS_FAILED(result))
        2274                 :     {
        2275               0 :       mIteratorStatus = eIsDone;
        2276               0 :       return result;
        2277                 :     }
        2278                 :
        2279               0 :     mIteratorStatus = eNext;
        2280                 :   }
        2281               0 :   else if (mPrevTextBlock)
        2282                 :   {
        2283               0 :     result = mIterator->PositionAt(mPrevTextBlock);
        2284                 :
        2285               0 :     if (NS_FAILED(result))
        2286                 :     {
        2287               0 :       mIteratorStatus = eIsDone;
        2288               0 :       return result;
        2289                 :     }
        2290                 :
        2291               0 :     mIteratorStatus = ePrev;
        2292                 :   }
        2293                 :   else
        2294               0 :     mIteratorStatus = eIsDone;
        2295                 :
        2296               0 :   return NS_OK;
        2297                 : }
        2298                 :
        2299                 : bool
        2300               0 : nsTextServicesDocument::DidSkip(nsIContentIterator* aFilteredIter)
        2301                 : {
        2302                 :   // We can assume here that the Iterator is a nsFilteredContentIterator because
        2303                 :   // all the iterator are created in CreateContentIterator which create a
        2304                 :   // nsFilteredContentIterator
        2305                 :   // So if the iterator bailed on one of the "filtered" content nodes then we
        2306                 :   // consider that to be a block and bail with true
        2307               0 :   if (aFilteredIter) {
        2308               0 :     nsFilteredContentIterator* filter = static_cast<nsFilteredContentIterator *>(aFilteredIter);
        2309               0 :     if (filter && filter->DidSkip()) {
        2310               0 :       return true;
        2311                 :     }
        2312                 :   }
        2313               0 :   return false;
        2314                 : }
        2315                 :
        2316                 : void
        2317               0 : nsTextServicesDocument::ClearDidSkip(nsIContentIterator* aFilteredIter)
        2318                 : {
        2319                 :   // Clear filter's skip flag
        2320               0 :   if (aFilteredIter) {
        2321               0 :     nsFilteredContentIterator* filter = static_cast<nsFilteredContentIterator *>(aFilteredIter);
        2322               0 :     filter->ClearDidSkip();
        2323                 :   }
        2324               0 : }
        2325                 :
        2326                 : bool
        2327               0 : nsTextServicesDocument::IsBlockNode(nsIContent *aContent)
        2328                 : {
        2329               0 :   if (!aContent) {
        2330               0 :     NS_ERROR("How did a null pointer get passed to IsBlockNode?");
        2331               0 :     return false;
        2332                 :   }
        2333                 :
        2334               0 :   nsIAtom *atom = aContent->Tag();
        2335                 :
        2336                 :   return (sAAtom       != atom &&
        2337                 :           sAddressAtom != atom &&
        2338                 :           sBigAtom     != atom &&
        2339                 :           sBlinkAtom   != atom &&
        2340                 :           sBAtom       != atom &&
        2341                 :           sCiteAtom    != atom &&
        2342                 :           sCodeAtom    != atom &&
        2343                 :           sDfnAtom     != atom &&
        2344                 :           sEmAtom      != atom &&
        2345                 :           sFontAtom    != atom &&
        2346                 :           sIAtom       != atom &&
        2347                 :           sKbdAtom     != atom &&
        2348                 :           sKeygenAtom  != atom &&
        2349                 :           sNobrAtom    != atom &&
        2350                 :           sSAtom       != atom &&
        2351                 :           sSampAtom    != atom &&
        2352                 :           sSmallAtom   != atom &&
        2353                 :           sSpacerAtom  != atom &&
        2354                 :           sSpanAtom    != atom &&
        2355                 :           sStrikeAtom  != atom &&
        2356                 :           sStrongAtom  != atom &&
        2357                 :           sSubAtom     != atom &&
        2358                 :           sSupAtom     != atom &&
        2359                 :           sTtAtom      != atom &&
        2360                 :           sUAtom       != atom &&
        2361                 :           sVarAtom     != atom &&
        2362               0 :           sWbrAtom     != atom);
        2363                 : }
        2364                 :
        2365                 : bool
        2366               0 : nsTextServicesDocument::HasSameBlockNodeParent(nsIContent *aContent1, nsIContent *aContent2)
        2367                 : {
        2368               0 :   nsIContent* p1 = aContent1->GetParent();
        2369               0 :   nsIContent* p2 = aContent2->GetParent();
        2370                 :
        2371                 :   // Quick test:
        2372                 :
        2373               0 :   if (p1 == p2)
        2374               0 :     return true;
        2375                 :
        2376                 :   // Walk up the parent hierarchy looking for closest block boundary node:
        2377                 :
        2378               0 :   while (p1 && !IsBlockNode(p1))
        2379                 :   {
        2380               0 :     p1 = p1->GetParent();
        2381                 :   }
        2382                 :
        2383               0 :   while (p2 && !IsBlockNode(p2))
        2384                 :   {
        2385               0 :     p2 = p2->GetParent();
        2386                 :   }
        2387                 :
        2388               0 :   return p1 == p2;
        2389                 : }
        2390                 :
        2391                 : bool
        2392               0 : nsTextServicesDocument::IsTextNode(nsIContent *aContent)
        2393                 : {
        2394               0 :   NS_ENSURE_TRUE(aContent, false);
        2395               0 :   return nsIDOMNode::TEXT_NODE == aContent->NodeType();
        2396                 : }
        2397                 :
        2398                 : bool
        2399               0 : nsTextServicesDocument::IsTextNode(nsIDOMNode *aNode)
        2400                 : {
        2401               0 :   NS_ENSURE_TRUE(aNode, false);
        2402                 :
        2403               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
        2404               0 :   return IsTextNode(content);
        2405                 : }
        2406                 :
        2407                 : nsresult
        2408               0 : nsTextServicesDocument::SetSelectionInternal(PRInt32 aOffset, PRInt32 aLength, bool aDoUpdate)
        2409                 : {
        2410               0 :   nsresult result = NS_OK;
        2411                 :
        2412               0 :   NS_ENSURE_TRUE(mSelCon && aOffset >= 0 && aLength >= 0, NS_ERROR_FAILURE);
        2413                 :
        2414               0 :   nsIDOMNode *sNode = 0, *eNode = 0;
        2415               0 :   PRInt32 i, sOffset = 0, eOffset = 0;
        2416                 :   OffsetEntry *entry;
        2417                 :
        2418                 :   // Find start of selection in node offset terms:
        2419                 :
        2420               0 :   for (i = 0; !sNode && i < PRInt32(mOffsetTable.Length()); i++)
        2421                 :   {
        2422               0 :     entry = mOffsetTable[i];
        2423               0 :     if (entry->mIsValid)
        2424                 :     {
        2425               0 :       if (entry->mIsInsertedText)
        2426                 :       {
        2427                 :         // Caret can only be placed at the end of an
        2428                 :         // inserted text offset entry, if the offsets
        2429                 :         // match exactly!
        2430                 :
        2431               0 :         if (entry->mStrOffset == aOffset)
        2432                 :         {
        2433               0 :           sNode   = entry->mNode;
        2434               0 :           sOffset = entry->mNodeOffset + entry->mLength;
        2435                 :         }
        2436                 :       }
        2437               0 :       else if (aOffset >= entry->mStrOffset)
        2438                 :       {
        2439               0 :         bool foundEntry = false;
        2440               0 :         PRInt32 strEndOffset = entry->mStrOffset + entry->mLength;
        2441                 :
        2442               0 :         if (aOffset < strEndOffset)
        2443               0 :           foundEntry = true;
        2444               0 :         else if (aOffset == strEndOffset)
        2445                 :         {
        2446                 :           // Peek after this entry to see if we have any
        2447                 :           // inserted text entries belonging to the same
        2448                 :           // entry->mNode. If so, we have to place the selection
        2449                 :           // after it!
        2450                 :
        2451               0 :           if ((i+1) < PRInt32(mOffsetTable.Length()))
        2452                 :           {
        2453               0 :             OffsetEntry *nextEntry = mOffsetTable[i+1];
        2454                 :
        2455               0 :             if (!nextEntry->mIsValid || nextEntry->mStrOffset != aOffset)
        2456                 :             {
        2457                 :               // Next offset entry isn't an exact match, so we'll
        2458                 :               // just use the current entry.
        2459               0 :               foundEntry = true;
        2460                 :             }
        2461                 :           }
        2462                 :         }
        2463                 :
        2464               0 :         if (foundEntry)
        2465                 :         {
        2466               0 :           sNode   = entry->mNode;
        2467               0 :           sOffset = entry->mNodeOffset + aOffset - entry->mStrOffset;
        2468                 :         }
        2469                 :       }
        2470                 :
        2471               0 :       if (sNode)
        2472                 :       {
        2473               0 :         mSelStartIndex  = i;
        2474               0 :         mSelStartOffset = aOffset;
        2475                 :       }
        2476                 :     }
        2477                 :   }
        2478                 :
        2479               0 :   NS_ENSURE_TRUE(sNode, NS_ERROR_FAILURE);
        2480                 :
        2481                 :   // XXX: If we ever get a SetSelection() method in nsIEditor, we should
        2482                 :   //      use it.
        2483                 :
        2484               0 :   nsCOMPtr<nsISelection> selection;
        2485                 :
        2486               0 :   if (aDoUpdate)
        2487                 :   {
        2488               0 :     result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
        2489                 :
        2490               0 :     NS_ENSURE_SUCCESS(result, result);
        2491                 :
        2492               0 :     result = selection->Collapse(sNode, sOffset);
        2493                 :
        2494               0 :     NS_ENSURE_SUCCESS(result, result);
        2495                 :    }
        2496                 :
        2497               0 :   if (aLength <= 0)
        2498                 :   {
        2499                 :     // We have a collapsed selection. (Caret)
        2500                 :
        2501               0 :     mSelEndIndex  = mSelStartIndex;
        2502               0 :     mSelEndOffset = mSelStartOffset;
        2503                 :
        2504                 :    //**** KDEBUG ****
        2505                 :    // printf("\n* Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        2506                 :    //**** KDEBUG ****
        2507                 :
        2508               0 :     return NS_OK;
        2509                 :   }
        2510                 :
        2511                 :   // Find the end of the selection in node offset terms:
        2512                 :
        2513               0 :   PRInt32 endOffset = aOffset + aLength;
        2514                 :
        2515               0 :   for (i = mOffsetTable.Length() - 1; !eNode && i >= 0; i--)
        2516                 :   {
        2517               0 :     entry = mOffsetTable[i];
        2518                 :
        2519               0 :     if (entry->mIsValid)
        2520                 :     {
        2521               0 :       if (entry->mIsInsertedText)
        2522                 :       {
        2523               0 :         if (entry->mStrOffset == eOffset)
        2524                 :         {
        2525                 :           // If the selection ends on an inserted text offset entry,
        2526                 :           // the selection includes the entire entry!
        2527                 :
        2528               0 :           eNode   = entry->mNode;
        2529               0 :           eOffset = entry->mNodeOffset + entry->mLength;
        2530                 :         }
        2531                 :       }
        2532               0 :       else if (endOffset >= entry->mStrOffset && endOffset <= entry->mStrOffset + entry->mLength)
        2533                 :       {
        2534               0 :         eNode   = entry->mNode;
        2535               0 :         eOffset = entry->mNodeOffset + endOffset - entry->mStrOffset;
        2536                 :       }
        2537                 :
        2538               0 :       if (eNode)
        2539                 :       {
        2540               0 :         mSelEndIndex  = i;
        2541               0 :         mSelEndOffset = endOffset;
        2542                 :       }
        2543                 :     }
        2544                 :   }
        2545                 :
        2546               0 :   if (aDoUpdate && eNode)
        2547                 :   {
        2548               0 :     result = selection->Extend(eNode, eOffset);
        2549                 :
        2550               0 :     NS_ENSURE_SUCCESS(result, result);
        2551                 :   }
        2552                 :
        2553                 :   //**** KDEBUG ****
        2554                 :   // printf("\n * Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
        2555                 :   //**** KDEBUG ****
        2556                 :
        2557               0 :   return result;
        2558                 : }
        2559                 :
        2560                 : nsresult
        2561               0 : nsTextServicesDocument::GetSelection(nsITextServicesDocument::TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength)
        2562                 : {
        2563                 :   nsresult result;
        2564                 :
        2565               0 :   NS_ENSURE_TRUE(aSelStatus && aSelOffset && aSelLength, NS_ERROR_NULL_POINTER);
        2566                 :
        2567               0 :   *aSelStatus = nsITextServicesDocument::eBlockNotFound;
        2568               0 :   *aSelOffset = -1;
        2569               0 :   *aSelLength = -1;
        2570                 :
        2571               0 :   NS_ENSURE_TRUE(mDOMDocument && mSelCon, NS_ERROR_FAILURE);
        2572                 :
        2573               0 :   if (mIteratorStatus == nsTextServicesDocument::eIsDone)
        2574               0 :     return NS_OK;
        2575                 :
        2576               0 :   nsCOMPtr<nsISelection> selection;
        2577                 :   bool isCollapsed;
        2578                 :
        2579               0 :   result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
        2580                 :
        2581               0 :   NS_ENSURE_SUCCESS(result, result);
        2582                 :
        2583               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
        2584                 :
        2585               0 :   result = selection->GetIsCollapsed(&isCollapsed);
        2586                 :
        2587               0 :   NS_ENSURE_SUCCESS(result, result);
        2588                 :
        2589                 :   // XXX: If we expose this method publicly, we need to
        2590                 :   //      add LOCK_DOC/UNLOCK_DOC calls!
        2591                 :
        2592                 :   // LOCK_DOC(this);
        2593                 :
        2594               0 :   if (isCollapsed)
        2595               0 :     result = GetCollapsedSelection(aSelStatus, aSelOffset, aSelLength);
        2596                 :   else
        2597               0 :     result = GetUncollapsedSelection(aSelStatus, aSelOffset, aSelLength);
        2598                 :
        2599                 :   // UNLOCK_DOC(this);
        2600                 :
        2601               0 :   return result;
        2602                 : }
        2603                 :
        2604                 : nsresult
        2605               0 : nsTextServicesDocument::GetCollapsedSelection(nsITextServicesDocument::TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength)
        2606                 : {
        2607                 :   nsresult result;
        2608               0 :   nsCOMPtr<nsISelection> selection;
        2609                 :
        2610               0 :   result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
        2611                 :
        2612               0 :   NS_ENSURE_SUCCESS(result, result);
        2613                 :
        2614               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
        2615                 :
        2616                 :   // The calling function should have done the GetIsCollapsed()
        2617                 :   // check already. Just assume it's collapsed!
        2618                 :
        2619               0 :   nsCOMPtr<nsIDOMRange> range;
        2620                 :   OffsetEntry *entry;
        2621               0 :   nsCOMPtr<nsIDOMNode> parent;
        2622                 :   PRInt32 offset, tableCount, i;
        2623                 :   PRInt32 e1s1, e2s1;
        2624                 :
        2625                 :   OffsetEntry *eStart, *eEnd;
        2626                 :   PRInt32 eStartOffset, eEndOffset;
        2627                 :
        2628                 :
        2629               0 :   *aSelStatus = nsITextServicesDocument::eBlockOutside;
        2630               0 :   *aSelOffset = *aSelLength = -1;
        2631                 :
        2632               0 :   tableCount = mOffsetTable.Length();
        2633                 :
        2634               0 :   if (tableCount == 0)
        2635               0 :     return NS_OK;
        2636                 :
        2637                 :   // Get pointers to the first and last offset entries
        2638                 :   // in the table.
        2639                 :
        2640               0 :   eStart = mOffsetTable[0];
        2641                 :
        2642               0 :   if (tableCount > 1)
        2643               0 :     eEnd = mOffsetTable[tableCount - 1];
        2644                 :   else
        2645               0 :     eEnd = eStart;
        2646                 :
        2647               0 :   eStartOffset = eStart->mNodeOffset;
        2648               0 :   eEndOffset   = eEnd->mNodeOffset + eEnd->mLength;
        2649                 :
        2650               0 :   result = selection->GetRangeAt(0, getter_AddRefs(range));
        2651                 :
        2652               0 :   NS_ENSURE_SUCCESS(result, result);
        2653                 :
        2654               0 :   result = range->GetStartContainer(getter_AddRefs(parent));
        2655                 :
        2656               0 :   NS_ENSURE_SUCCESS(result, result);
        2657                 :
        2658               0 :   result = range->GetStartOffset(&offset);
        2659                 :
        2660               0 :   NS_ENSURE_SUCCESS(result, result);
        2661                 :
        2662                 :   e1s1 = nsContentUtils::ComparePoints(eStart->mNode, eStartOffset,
        2663               0 :                                        parent, offset);
        2664                 :   e2s1 = nsContentUtils::ComparePoints(eEnd->mNode, eEndOffset,
        2665               0 :                                        parent, offset);
        2666                 :
        2667               0 :   if (e1s1 > 0 || e2s1 < 0)
        2668                 :   {
        2669                 :     // We're done if the caret is outside the
        2670                 :     // current text block.
        2671                 :
        2672               0 :     return NS_OK;
        2673                 :   }
        2674                 :
        2675               0 :   if (IsTextNode(parent))
        2676                 :   {
        2677                 :     // Good news, the caret is in a text node. Look
        2678                 :     // through the offset table for the entry that
        2679                 :     // matches its parent and offset.
        2680                 :
        2681               0 :     for (i = 0; i < tableCount; i++)
        2682                 :     {
        2683               0 :       entry = mOffsetTable[i];
        2684                 :
        2685               0 :       NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
        2686                 :
        2687               0 :       if (entry->mNode == parent.get() &&
        2688                 :           entry->mNodeOffset <= offset && offset <= (entry->mNodeOffset + entry->mLength))
        2689                 :       {
        2690               0 :         *aSelStatus = nsITextServicesDocument::eBlockContains;
        2691               0 :         *aSelOffset = entry->mStrOffset + (offset - entry->mNodeOffset);
        2692               0 :         *aSelLength = 0;
        2693                 :
        2694               0 :         return NS_OK;
        2695                 :       }
        2696                 :     }
        2697                 :
        2698                 :     // If we get here, we didn't find a text node entry
        2699                 :     // in our offset table that matched.
        2700                 :
        2701               0 :     return NS_ERROR_FAILURE;
        2702                 :   }
        2703                 :
        2704                 :   // The caret is in our text block, but it's positioned in some
        2705                 :   // non-text node (ex. <b>). Create a range based on the start
        2706                 :   // and end of the text block, then create an iterator based on
        2707                 :   // this range, with its initial position set to the closest
        2708                 :   // child of this non-text node. Then look for the closest text
        2709                 :   // node.
        2710                 :
        2711               0 :   nsCOMPtr<nsIDOMNode> node, saveNode;
        2712               0 :   nsCOMPtr<nsIDOMNodeList> children;
        2713               0 :   nsCOMPtr<nsIContentIterator> iter;
        2714                 :   bool hasChildren;
        2715                 :
        2716               0 :   result = CreateRange(eStart->mNode, eStartOffset, eEnd->mNode, eEndOffset, getter_AddRefs(range));
        2717                 :
        2718               0 :   NS_ENSURE_SUCCESS(result, result);
        2719                 :
        2720               0 :   result = CreateContentIterator(range, getter_AddRefs(iter));
        2721                 :
        2722               0 :   NS_ENSURE_SUCCESS(result, result);
        2723                 :
        2724               0 :   result = parent->HasChildNodes(&hasChildren);
        2725                 :
        2726               0 :   NS_ENSURE_SUCCESS(result, result);
        2727                 :
        2728               0 :   if (hasChildren)
        2729                 :   {
        2730                 :     // XXX: We need to make sure that all of parent's
        2731                 :     //      children are in the text block.
        2732                 :
        2733                 :     // If the parent has children, position the iterator
        2734                 :     // on the child that is to the left of the offset.
        2735                 :
        2736               0 :     PRUint32 childIndex = (PRUint32)offset;
        2737                 :
        2738               0 :     result = parent->GetChildNodes(getter_AddRefs(children));
        2739                 :
        2740               0 :     NS_ENSURE_SUCCESS(result, result);
        2741                 :
        2742               0 :     NS_ENSURE_TRUE(children, NS_ERROR_FAILURE);
        2743                 :
        2744               0 :     if (childIndex > 0)
        2745                 :     {
        2746                 :       PRUint32 numChildren;
        2747                 :
        2748               0 :       result = children->GetLength(&numChildren);
        2749                 :
        2750               0 :       NS_ENSURE_SUCCESS(result, result);
        2751                 :
        2752               0 :       NS_ASSERTION(childIndex <= numChildren, "Invalid selection offset!");
        2753                 :
        2754               0 :       if (childIndex > numChildren)
        2755               0 :         childIndex = numChildren;
        2756                 :
        2757               0 :       childIndex -= 1;
        2758                 :     }
        2759                 :
        2760               0 :     result = children->Item(childIndex, getter_AddRefs(saveNode));
        2761                 :
        2762               0 :     NS_ENSURE_SUCCESS(result, result);
        2763                 :
        2764               0 :     nsCOMPtr<nsIContent> content(do_QueryInterface(saveNode));
        2765                 :
        2766               0 :     NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
        2767                 :
        2768               0 :     result = iter->PositionAt(content);
        2769                 :
        2770               0 :     NS_ENSURE_SUCCESS(result, result);
        2771                 :   }
        2772                 :   else
        2773                 :   {
        2774                 :     // The parent has no children, so position the iterator
        2775                 :     // on the parent.
        2776                 :
        2777               0 :     nsCOMPtr<nsIContent> content(do_QueryInterface(parent));
        2778                 :
        2779               0 :     NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
        2780                 :
        2781               0 :     result = iter->PositionAt(content);
        2782                 :
        2783               0 :     NS_ENSURE_SUCCESS(result, result);
        2784                 :
        2785               0 :     saveNode = parent;
        2786                 :   }
        2787                 :
        2788                 :   // Now iterate to the left, towards the beginning of
        2789                 :   // the text block, to find the first text node you
        2790                 :   // come across.
        2791                 :
        2792               0 :   while (!iter->IsDone())
        2793                 :   {
        2794               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
        2795                 :
        2796               0 :     if (IsTextNode(content))
        2797                 :     {
        2798               0 :       node = do_QueryInterface(content);
        2799                 :
        2800               0 :       NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
        2801                 :
        2802                 :       break;
        2803                 :     }
        2804                 :
        2805               0 :     node = nsnull;
        2806                 :
        2807               0 :     iter->Prev();
        2808                 :   }
        2809                 :
        2810               0 :   if (node)
        2811                 :   {
        2812                 :     // We found a node, now set the offset to the end
        2813                 :     // of the text node.
        2814                 :
        2815               0 :     nsAutoString str;
        2816               0 :     result = node->GetNodeValue(str);
        2817                 :
        2818               0 :     NS_ENSURE_SUCCESS(result, result);
        2819                 :
        2820               0 :     offset = str.Length();
        2821                 :   }
        2822                 :   else
        2823                 :   {
        2824                 :     // We should never really get here, but I'm paranoid.
        2825                 :
        2826                 :     // We didn't find a text node above, so iterate to
        2827                 :     // the right, towards the end of the text block, looking
        2828                 :     // for a text node.
        2829                 :
        2830                 :     {
        2831               0 :       nsCOMPtr<nsIContent> content(do_QueryInterface(saveNode));
        2832                 :
        2833               0 :       result = iter->PositionAt(content);
        2834                 :
        2835               0 :       NS_ENSURE_SUCCESS(result, result);
        2836                 :     }
        2837                 :
        2838               0 :     while (!iter->IsDone())
        2839                 :     {
        2840               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
        2841                 :
        2842               0 :       if (IsTextNode(content))
        2843                 :       {
        2844               0 :         node = do_QueryInterface(content);
        2845                 :
        2846               0 :         NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
        2847                 :
        2848                 :         break;
        2849                 :       }
        2850                 :
        2851               0 :       node = nsnull;
        2852                 :
        2853               0 :       iter->Next();
        2854                 :     }
        2855                 :
        2856               0 :     NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
        2857                 :
        2858                 :     // We found a text node, so set the offset to
        2859                 :     // the begining of the node.
        2860                 :
        2861               0 :     offset = 0;
        2862                 :   }
        2863                 :
        2864               0 :   for (i = 0; i < tableCount; i++)
        2865                 :   {
        2866               0 :     entry = mOffsetTable[i];
        2867                 :
        2868               0 :     NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
        2869                 :
        2870               0 :     if (entry->mNode == node.get() &&
        2871                 :         entry->mNodeOffset <= offset && offset <= (entry->mNodeOffset + entry->mLength))
        2872                 :     {
        2873               0 :       *aSelStatus = nsITextServicesDocument::eBlockContains;
        2874               0 :       *aSelOffset = entry->mStrOffset + (offset - entry->mNodeOffset);
        2875               0 :       *aSelLength = 0;
        2876                 :
        2877                 :       // Now move the caret so that it is actually in the text node.
        2878                 :       // We do this to keep things in sync.
        2879                 :       //
        2880                 :       // In most cases, the user shouldn't see any movement in the caret
        2881                 :       // on screen.
        2882                 :
        2883               0 :       result = SetSelectionInternal(*aSelOffset, *aSelLength, true);
        2884                 :
        2885               0 :       return result;
        2886                 :     }
        2887                 :   }
        2888                 :
        2889               0 :   return NS_ERROR_FAILURE;
        2890                 : }
        2891                 :
        2892                 : nsresult
        2893               0 : nsTextServicesDocument::GetUncollapsedSelection(nsITextServicesDocument::TSDBlockSelectionStatus *aSelStatus, PRInt32 *aSelOffset, PRInt32 *aSelLength)
        2894                 : {
        2895                 :   nsresult result;
        2896                 :
        2897               0 :   nsCOMPtr<nsISelection> selection;
        2898               0 :   nsCOMPtr<nsIDOMRange> range;
        2899                 :   OffsetEntry *entry;
        2900                 :
        2901               0 :   result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
        2902                 :
        2903               0 :   NS_ENSURE_SUCCESS(result, result);
        2904                 :
        2905               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
        2906                 :
        2907                 :   // It is assumed that the calling function has made sure that the
        2908                 :   // selection is not collapsed, and that the input params to this
        2909                 :   // method are initialized to some defaults.
        2910                 :
        2911               0 :   nsCOMPtr<nsIDOMNode> startParent, endParent;
        2912                 :   PRInt32 startOffset, endOffset;
        2913                 :   PRInt32 rangeCount, tableCount, i;
        2914                 :   PRInt32 e1s1, e1s2, e2s1, e2s2;
        2915                 :
        2916                 :   OffsetEntry *eStart, *eEnd;
        2917                 :   PRInt32 eStartOffset, eEndOffset;
        2918                 :
        2919               0 :   tableCount = mOffsetTable.Length();
        2920                 :
        2921                 :   // Get pointers to the first and last offset entries
        2922                 :   // in the table.
        2923                 :
        2924               0 :   eStart = mOffsetTable[0];
        2925                 :
        2926               0 :   if (tableCount > 1)
        2927               0 :     eEnd = mOffsetTable[tableCount - 1];
        2928                 :   else
        2929               0 :     eEnd = eStart;
        2930                 :
        2931               0 :   eStartOffset = eStart->mNodeOffset;
        2932               0 :   eEndOffset   = eEnd->mNodeOffset + eEnd->mLength;
        2933                 :
        2934               0 :   result = selection->GetRangeCount(&rangeCount);
        2935                 :
        2936               0 :   NS_ENSURE_SUCCESS(result, result);
        2937                 :
        2938                 :   // Find the first range in the selection that intersects
        2939                 :   // the current text block.
        2940                 :
        2941               0 :   for (i = 0; i < rangeCount; i++)
        2942                 :   {
        2943               0 :     result = selection->GetRangeAt(i, getter_AddRefs(range));
        2944                 :
        2945               0 :     NS_ENSURE_SUCCESS(result, result);
        2946                 :
        2947                 :     result = GetRangeEndPoints(range,
        2948               0 :                                getter_AddRefs(startParent), &startOffset,
        2949               0 :                                getter_AddRefs(endParent), &endOffset);
        2950                 :
        2951               0 :     NS_ENSURE_SUCCESS(result, result);
        2952                 :
        2953                 :     e1s2 = nsContentUtils::ComparePoints(eStart->mNode, eStartOffset,
        2954               0 :                                          endParent, endOffset);
        2955                 :     e2s1 = nsContentUtils::ComparePoints(eEnd->mNode, eEndOffset,
        2956               0 :                                          startParent, startOffset);
        2957                 :
        2958                 :     // Break out of the loop if the text block intersects the current range.
        2959                 :
        2960               0 :     if (e1s2 <= 0 && e2s1 >= 0)
        2961               0 :       break;
        2962                 :   }
        2963                 :
        2964                 :   // We're done if we didn't find an intersecting range.
        2965                 :
        2966               0 :   if (rangeCount < 1 || e1s2 > 0 || e2s1 < 0)
        2967                 :   {
        2968               0 :     *aSelStatus = nsITextServicesDocument::eBlockOutside;
        2969               0 :     *aSelOffset = *aSelLength = -1;
        2970               0 :     return NS_OK;
        2971                 :   }
        2972                 :
        2973                 :   // Now that we have an intersecting range, find out more info:
        2974                 :
        2975                 :   e1s1 = nsContentUtils::ComparePoints(eStart->mNode, eStartOffset,
        2976               0 :                                        startParent, startOffset);
        2977                 :   e2s2 = nsContentUtils::ComparePoints(eEnd->mNode, eEndOffset,
        2978               0 :                                        endParent, endOffset);
        2979                 :
        2980               0 :   if (rangeCount > 1)
        2981                 :   {
        2982                 :     // There are multiple selection ranges, we only deal
        2983                 :     // with the first one that intersects the current,
        2984                 :     // text block, so mark this a as a partial.
        2985                 :
        2986               0 :     *aSelStatus = nsITextServicesDocument::eBlockPartial;
        2987                 :   }
        2988               0 :   else if (e1s1 > 0 && e2s2 < 0)
        2989                 :   {
        2990                 :     // The range extends beyond the start and
        2991                 :     // end of the current text block.
        2992                 :
        2993               0 :     *aSelStatus = nsITextServicesDocument::eBlockInside;
        2994                 :   }
        2995               0 :   else if (e1s1 <= 0 && e2s2 >= 0)
        2996                 :   {
        2997                 :     // The current text block contains the entire
        2998                 :     // range.
        2999                 :
        3000               0 :     *aSelStatus = nsITextServicesDocument::eBlockContains;
        3001                 :   }
        3002                 :   else
        3003                 :   {
        3004                 :     // The range partially intersects the block.
        3005                 :
        3006               0 :     *aSelStatus = nsITextServicesDocument::eBlockPartial;
        3007                 :   }
        3008                 :
        3009                 :   // Now create a range based on the intersection of the
        3010                 :   // text block and range:
        3011                 :
        3012               0 :   nsCOMPtr<nsIDOMNode> p1, p2;
        3013                 :   PRInt32     o1,  o2;
        3014                 :
        3015                 :   // The start of the range will be the rightmost
        3016                 :   // start node.
        3017                 :
        3018               0 :   if (e1s1 >= 0)
        3019                 :   {
        3020               0 :     p1 = do_QueryInterface(eStart->mNode);
        3021               0 :     o1 = eStartOffset;
        3022                 :   }
        3023                 :   else
        3024                 :   {
        3025               0 :     p1 = startParent;
        3026               0 :     o1 = startOffset;
        3027                 :   }
        3028                 :
        3029                 :   // The end of the range will be the leftmost
        3030                 :   // end node.
        3031                 :
        3032               0 :   if (e2s2 <= 0)
        3033                 :   {
        3034               0 :     p2 = do_QueryInterface(eEnd->mNode);
        3035               0 :     o2 = eEndOffset;
        3036                 :   }
        3037                 :   else
        3038                 :   {
        3039               0 :     p2 = endParent;
        3040               0 :     o2 = endOffset;
        3041                 :   }
        3042                 :
        3043               0 :   result = CreateRange(p1, o1, p2, o2, getter_AddRefs(range));
        3044                 :
        3045               0 :   NS_ENSURE_SUCCESS(result, result);
        3046                 :
        3047                 :   // Now iterate over this range to figure out the selection's
        3048                 :   // block offset and length.
        3049                 :
        3050               0 :   nsCOMPtr<nsIContentIterator> iter;
        3051                 :
        3052               0 :   result = CreateContentIterator(range, getter_AddRefs(iter));
        3053                 :
        3054               0 :   NS_ENSURE_SUCCESS(result, result);
        3055                 :
        3056                 :   // Find the first text node in the range.
        3057                 :
        3058                 :   bool found;
        3059               0 :   nsCOMPtr<nsIContent> content;
        3060                 :
        3061               0 :   iter->First();
        3062                 :
        3063               0 :   if (!IsTextNode(p1))
        3064                 :   {
        3065               0 :     found = false;
        3066                 :
        3067               0 :     while (!iter->IsDone())
        3068                 :     {
        3069               0 :       content = do_QueryInterface(iter->GetCurrentNode());
        3070                 :
        3071               0 :       if (IsTextNode(content))
        3072                 :       {
        3073               0 :         p1 = do_QueryInterface(content);
        3074                 :
        3075               0 :         NS_ENSURE_TRUE(p1, NS_ERROR_FAILURE);
        3076                 :
        3077               0 :         o1 = 0;
        3078               0 :         found = true;
        3079                 :
        3080               0 :         break;
        3081                 :       }
        3082                 :
        3083               0 :       iter->Next();
        3084                 :     }
        3085                 :
        3086               0 :     NS_ENSURE_TRUE(found, NS_ERROR_FAILURE);
        3087                 :   }
        3088                 :
        3089                 :   // Find the last text node in the range.
        3090                 :
        3091               0 :   iter->Last();
        3092                 :
        3093               0 :   if (! IsTextNode(p2))
        3094                 :   {
        3095               0 :     found = false;
        3096                 :
        3097               0 :     while (!iter->IsDone())
        3098                 :     {
        3099               0 :       content = do_QueryInterface(iter->GetCurrentNode());
        3100                 :
        3101               0 :       if (IsTextNode(content))
        3102                 :       {
        3103               0 :         p2 = do_QueryInterface(content);
        3104                 :
        3105               0 :         NS_ENSURE_TRUE(p2, NS_ERROR_FAILURE);
        3106                 :
        3107               0 :         nsString str;
        3108                 :
        3109               0 :         result = p2->GetNodeValue(str);
        3110                 :
        3111               0 :         NS_ENSURE_SUCCESS(result, result);
        3112                 :
        3113               0 :         o2 = str.Length();
        3114               0 :         found = true;
        3115                 :
        3116               0 :         break;
        3117                 :       }
        3118                 :
        3119               0 :       iter->Prev();
        3120                 :     }
        3121                 :
        3122               0 :     NS_ENSURE_TRUE(found, NS_ERROR_FAILURE);
        3123                 :   }
        3124                 :
        3125               0 :   found    = false;
        3126               0 :   *aSelLength = 0;
        3127                 :
        3128               0 :   for (i = 0; i < tableCount; i++)
        3129                 :   {
        3130               0 :     entry = mOffsetTable[i];
        3131                 :
        3132               0 :     NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
        3133                 :
        3134               0 :     if (!found)
        3135                 :     {
        3136               0 :       if (entry->mNode == p1.get() &&
        3137                 :           entry->mNodeOffset <= o1 && o1 <= (entry->mNodeOffset + entry->mLength))
        3138                 :       {
        3139               0 :         *aSelOffset = entry->mStrOffset + (o1 - entry->mNodeOffset);
        3140                 :
        3141               0 :         if (p1 == p2 &&
        3142                 :             entry->mNodeOffset <= o2 && o2 <= (entry->mNodeOffset + entry->mLength))
        3143                 :         {
        3144                 :           // The start and end of the range are in the same offset
        3145                 :           // entry. Calculate the length of the range then we're done.
        3146                 :
        3147               0 :           *aSelLength = o2 - o1;
        3148               0 :           break;
        3149                 :         }
        3150                 :         else
        3151                 :         {
        3152                 :           // Add the length of the sub string in this offset entry
        3153                 :           // that follows the start of the range.
        3154                 :
        3155               0 :           *aSelLength = entry->mLength - (o1 - entry->mNodeOffset);
        3156                 :         }
        3157                 :
        3158               0 :         found = true;
        3159                 :       }
        3160                 :     }
        3161                 :     else // found
        3162                 :     {
        3163               0 :       if (entry->mNode == p2.get() &&
        3164                 :           entry->mNodeOffset <= o2 && o2 <= (entry->mNodeOffset + entry->mLength))
        3165                 :       {
        3166                 :         // We found the end of the range. Calculate the length of the
        3167                 :         // sub string that is before the end of the range, then we're done.
        3168                 :
        3169               0 :         *aSelLength += o2 - entry->mNodeOffset;
        3170               0 :         break;
        3171                 :       }
        3172                 :       else
        3173                 :       {
        3174                 :         // The entire entry must be in the range.
        3175                 :
        3176               0 :         *aSelLength += entry->mLength;
        3177                 :       }
        3178                 :     }
        3179                 :   }
        3180                 :
        3181               0 :   return result;
        3182                 : }
        3183                 :
        3184                 : bool
        3185               0 : nsTextServicesDocument::SelectionIsCollapsed()
        3186                 : {
        3187               0 :   return(mSelStartIndex == mSelEndIndex && mSelStartOffset == mSelEndOffset);
        3188                 : }
        3189                 :
        3190                 : bool
        3191               0 : nsTextServicesDocument::SelectionIsValid()
        3192                 : {
        3193               0 :   return(mSelStartIndex >= 0);
        3194                 : }
        3195                 :
        3196                 : nsresult
        3197               0 : nsTextServicesDocument::GetRangeEndPoints(nsIDOMRange *aRange,
        3198                 :                                           nsIDOMNode **aStartParent, PRInt32 *aStartOffset,
        3199                 :                                           nsIDOMNode **aEndParent, PRInt32 *aEndOffset)
        3200                 : {
        3201                 :   nsresult result;
        3202                 :
        3203               0 :   NS_ENSURE_TRUE(aRange && aStartParent && aStartOffset && aEndParent && aEndOffset, NS_ERROR_NULL_POINTER);
        3204                 :
        3205               0 :   result = aRange->GetStartContainer(aStartParent);
        3206                 :
        3207               0 :   NS_ENSURE_SUCCESS(result, result);
        3208                 :
        3209               0 :   NS_ENSURE_TRUE(aStartParent, NS_ERROR_FAILURE);
        3210                 :
        3211               0 :   result = aRange->GetStartOffset(aStartOffset);
        3212                 :
        3213               0 :   NS_ENSURE_SUCCESS(result, result);
        3214                 :
        3215               0 :   result = aRange->GetEndContainer(aEndParent);
        3216                 :
        3217               0 :   NS_ENSURE_SUCCESS(result, result);
        3218                 :
        3219               0 :   NS_ENSURE_TRUE(aEndParent, NS_ERROR_FAILURE);
        3220                 :
        3221               0 :   result = aRange->GetEndOffset(aEndOffset);
        3222                 :
        3223               0 :   return result;
        3224                 : }
        3225                 :
        3226                 :
        3227                 : nsresult
        3228               0 : nsTextServicesDocument::CreateRange(nsIDOMNode *aStartParent, PRInt32 aStartOffset,
        3229                 :                                     nsIDOMNode *aEndParent, PRInt32 aEndOffset,
        3230                 :                                     nsIDOMRange **aRange)
        3231                 : {
        3232                 :   return nsRange::CreateRange(aStartParent, aStartOffset, aEndParent,
        3233               0 :                               aEndOffset, aRange);
        3234                 : }
        3235                 :
        3236                 : nsresult
        3237               0 : nsTextServicesDocument::FirstTextNode(nsIContentIterator *aIterator,
        3238                 :                                       TSDIteratorStatus *aIteratorStatus)
        3239                 : {
        3240               0 :   if (aIteratorStatus)
        3241               0 :     *aIteratorStatus = nsTextServicesDocument::eIsDone;
        3242                 :
        3243               0 :   aIterator->First();
        3244                 :
        3245               0 :   while (!aIterator->IsDone()) {
        3246               0 :     if (aIterator->GetCurrentNode()->NodeType() == nsIDOMNode::TEXT_NODE) {
        3247               0 :       if (aIteratorStatus)
        3248               0 :         *aIteratorStatus = nsTextServicesDocument::eValid;
        3249               0 :       break;
        3250                 :     }
        3251                 :
        3252               0 :     aIterator->Next();
        3253                 :   }
        3254                 :
        3255               0 :   return NS_OK;
        3256                 : }
        3257                 :
        3258                 : nsresult
        3259               0 : nsTextServicesDocument::LastTextNode(nsIContentIterator *aIterator,
        3260                 :                                      TSDIteratorStatus *aIteratorStatus)
        3261                 : {
        3262               0 :   if (aIteratorStatus)
        3263               0 :     *aIteratorStatus = nsTextServicesDocument::eIsDone;
        3264                 :
        3265               0 :   aIterator->Last();
        3266                 :
        3267               0 :   while (!aIterator->IsDone()) {
        3268               0 :     if (aIterator->GetCurrentNode()->NodeType() == nsIDOMNode::TEXT_NODE) {
        3269               0 :       if (aIteratorStatus)
        3270               0 :         *aIteratorStatus = nsTextServicesDocument::eValid;
        3271               0 :       break;
        3272                 :     }
        3273                 :
        3274               0 :     aIterator->Prev();
        3275                 :   }
        3276                 :
        3277               0 :   return NS_OK;
        3278                 : }
        3279                 :
        3280                 : nsresult
        3281               0 : nsTextServicesDocument::FirstTextNodeInCurrentBlock(nsIContentIterator *iter)
        3282                 : {
        3283               0 :   NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
        3284                 :
        3285               0 :   ClearDidSkip(iter);
        3286                 :
        3287               0 :   nsCOMPtr<nsIContent> last;
        3288                 :
        3289                 :   // Walk backwards over adjacent text nodes until
        3290                 :   // we hit a block boundary:
        3291                 :
        3292               0 :   while (!iter->IsDone())
        3293                 :   {
        3294               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
        3295                 :
        3296               0 :     if (IsTextNode(content))
        3297                 :     {
        3298               0 :       if (!last || HasSameBlockNodeParent(content, last))
        3299               0 :         last = content;
        3300                 :       else
        3301                 :       {
        3302                 :         // We're done, the current text node is in a
        3303                 :         // different block.
        3304                 :         break;
        3305                 :       }
        3306                 :     }
        3307               0 :     else if (last && IsBlockNode(content))
        3308                 :       break;
        3309                 :
        3310               0 :     iter->Prev();
        3311                 :
        3312               0 :     if (DidSkip(iter))
        3313                 :       break;
        3314                 :   }
        3315                 :
        3316               0 :   if (last)
        3317               0 :     iter->PositionAt(last);
        3318                 :
        3319                 :   // XXX: What should we return if last is null?
        3320                 :
        3321               0 :   return NS_OK;
        3322                 : }
        3323                 :
        3324                 : nsresult
        3325               0 : nsTextServicesDocument::FirstTextNodeInPrevBlock(nsIContentIterator *aIterator)
        3326                 : {
        3327               0 :   nsCOMPtr<nsIContent> content;
        3328                 :   nsresult result;
        3329                 :
        3330               0 :   NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
        3331                 :
        3332                 :   // XXX: What if mIterator is not currently on a text node?
        3333                 :
        3334                 :   // Make sure mIterator is pointing to the first text node in the
        3335                 :   // current block:
        3336                 :
        3337               0 :   result = FirstTextNodeInCurrentBlock(aIterator);
        3338                 :
        3339               0 :   NS_ENSURE_SUCCESS(result, NS_ERROR_FAILURE);
        3340                 :
        3341                 :   // Point mIterator to the first node before the first text node:
        3342                 :
        3343               0 :   aIterator->Prev();
        3344                 :
        3345               0 :   if (aIterator->IsDone())
        3346               0 :     return NS_ERROR_FAILURE;
        3347                 :
        3348                 :   // Now find the first text node of the next block:
        3349                 :
        3350               0 :   return FirstTextNodeInCurrentBlock(aIterator);
        3351                 : }
        3352                 :
        3353                 : nsresult
        3354               0 : nsTextServicesDocument::FirstTextNodeInNextBlock(nsIContentIterator *aIterator)
        3355                 : {
        3356               0 :   nsCOMPtr<nsIContent> prev;
        3357               0 :   bool crossedBlockBoundary = false;
        3358                 :
        3359               0 :   NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
        3360                 :
        3361               0 :   ClearDidSkip(aIterator);
        3362                 :
        3363               0 :   while (!aIterator->IsDone())
        3364                 :   {
        3365               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aIterator->GetCurrentNode());
        3366                 :
        3367               0 :     if (IsTextNode(content))
        3368                 :     {
        3369               0 :       if (!crossedBlockBoundary && (!prev || HasSameBlockNodeParent(prev, content)))
        3370               0 :         prev = content;
        3371                 :       else
        3372                 :         break;
        3373                 :     }
        3374               0 :     else if (!crossedBlockBoundary && IsBlockNode(content))
        3375               0 :       crossedBlockBoundary = true;
        3376                 :
        3377               0 :     aIterator->Next();
        3378                 :
        3379               0 :     if (!crossedBlockBoundary && DidSkip(aIterator))
        3380               0 :       crossedBlockBoundary = true;
        3381                 :   }
        3382                 :
        3383               0 :   return NS_OK;
        3384                 : }
        3385                 :
        3386                 : nsresult
        3387               0 : nsTextServicesDocument::GetFirstTextNodeInPrevBlock(nsIContent **aContent)
        3388                 : {
        3389                 :   nsresult result;
        3390                 :
        3391               0 :   NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER);
        3392                 :
        3393               0 :   *aContent = 0;
        3394                 :
        3395                 :   // Save the iterator's current content node so we can restore
        3396                 :   // it when we are done:
        3397                 :
        3398               0 :   nsINode* node = mIterator->GetCurrentNode();
        3399                 :
        3400               0 :   result = FirstTextNodeInPrevBlock(mIterator);
        3401                 :
        3402               0 :   if (NS_FAILED(result))
        3403                 :   {
        3404                 :     // Try to restore the iterator before returning.
        3405               0 :     mIterator->PositionAt(node);
        3406               0 :     return result;
        3407                 :   }
        3408                 :
        3409               0 :   if (!mIterator->IsDone())
        3410                 :   {
        3411               0 :     nsCOMPtr<nsIContent> current = do_QueryInterface(mIterator->GetCurrentNode());
        3412               0 :     current.forget(aContent);
        3413                 :   }
        3414                 :
        3415                 :   // Restore the iterator:
        3416                 :
        3417               0 :   return mIterator->PositionAt(node);
        3418                 : }
        3419                 :
        3420                 : nsresult
        3421               0 : nsTextServicesDocument::GetFirstTextNodeInNextBlock(nsIContent **aContent)
        3422                 : {
        3423                 :   nsresult result;
        3424                 :
        3425               0 :   NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER);
        3426                 :
        3427               0 :   *aContent = 0;
        3428                 :
        3429                 :   // Save the iterator's current content node so we can restore
        3430                 :   // it when we are done:
        3431                 :
        3432               0 :   nsINode* node = mIterator->GetCurrentNode();
        3433                 :
        3434               0 :   result = FirstTextNodeInNextBlock(mIterator);
        3435                 :
        3436               0 :   if (NS_FAILED(result))
        3437                 :   {
        3438                 :     // Try to restore the iterator before returning.
        3439               0 :     mIterator->PositionAt(node);
        3440               0 :     return result;
        3441                 :   }
        3442                 :
        3443               0 :   if (!mIterator->IsDone())
        3444                 :   {
        3445               0 :     nsCOMPtr<nsIContent> current = do_QueryInterface(mIterator->GetCurrentNode());
        3446               0 :     current.forget(aContent);
        3447                 :   }
        3448                 :
        3449                 :   // Restore the iterator:
        3450               0 :   return mIterator->PositionAt(node);
        3451                 : }
        3452                 :
        3453                 : nsresult
        3454               0 : nsTextServicesDocument::CreateOffsetTable(nsTArray<OffsetEntry*> *aOffsetTable,
        3455                 :                                           nsIContentIterator *aIterator,
        3456                 :                                           TSDIteratorStatus *aIteratorStatus,
        3457                 :                                           nsIDOMRange *aIterRange,
        3458                 :                                           nsString *aStr)
        3459                 : {
        3460               0 :   nsresult result = NS_OK;
        3461                 :
        3462               0 :   nsCOMPtr<nsIContent> first;
        3463               0 :   nsCOMPtr<nsIContent> prev;
        3464                 :
        3465               0 :   NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER);
        3466                 :
        3467               0 :   ClearOffsetTable(aOffsetTable);
        3468                 :
        3469               0 :   if (aStr)
        3470               0 :     aStr->Truncate();
        3471                 :
        3472               0 :   if (*aIteratorStatus == nsTextServicesDocument::eIsDone)
        3473               0 :     return NS_OK;
        3474                 :
        3475                 :   // If we have an aIterRange, retrieve the endpoints so
        3476                 :   // they can be used in the while loop below to trim entries
        3477                 :   // for text nodes that are partially selected by aIterRange.
        3478                 :
        3479               0 :   nsCOMPtr<nsIDOMNode> rngStartNode, rngEndNode;
        3480               0 :   PRInt32 rngStartOffset = 0, rngEndOffset = 0;
        3481                 :
        3482               0 :   if (aIterRange)
        3483                 :   {
        3484                 :     result = GetRangeEndPoints(aIterRange,
        3485               0 :                                getter_AddRefs(rngStartNode), &rngStartOffset,
        3486               0 :                                getter_AddRefs(rngEndNode), &rngEndOffset);
        3487                 :
        3488               0 :     NS_ENSURE_SUCCESS(result, result);
        3489                 :   }
        3490                 :
        3491                 :   // The text service could have added text nodes to the beginning
        3492                 :   // of the current block and called this method again. Make sure
        3493                 :   // we really are at the beginning of the current block:
        3494                 :
        3495               0 :   result = FirstTextNodeInCurrentBlock(aIterator);
        3496                 :
        3497               0 :   NS_ENSURE_SUCCESS(result, result);
        3498                 :
        3499               0 :   PRInt32 offset = 0;
        3500                 :
        3501               0 :   ClearDidSkip(aIterator);
        3502                 :
        3503               0 :   while (!aIterator->IsDone())
        3504                 :   {
        3505               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(aIterator->GetCurrentNode());
        3506                 :
        3507               0 :     if (IsTextNode(content))
        3508                 :     {
        3509               0 :       if (!prev || HasSameBlockNodeParent(prev, content))
        3510                 :       {
        3511               0 :         nsCOMPtr<nsIDOMNode> node = do_QueryInterface(content);
        3512                 :
        3513               0 :         if (node)
        3514                 :         {
        3515               0 :           nsString str;
        3516                 :
        3517               0 :           result = node->GetNodeValue(str);
        3518                 :
        3519               0 :           NS_ENSURE_SUCCESS(result, result);
        3520                 :
        3521                 :           // Add an entry for this text node into the offset table:
        3522                 :
        3523               0 :           OffsetEntry *entry = new OffsetEntry(node, offset, str.Length());
        3524               0 :           aOffsetTable->AppendElement(entry);
        3525                 :
        3526                 :           // If one or both of the endpoints of the iteration range
        3527                 :           // are in the text node for this entry, make sure the entry
        3528                 :           // only accounts for the portion of the text node that is
        3529                 :           // in the range.
        3530                 :
        3531               0 :           PRInt32 startOffset = 0;
        3532               0 :           PRInt32 endOffset   = str.Length();
        3533               0 :           bool adjustStr    = false;
        3534                 :
        3535               0 :           if (entry->mNode == rngStartNode)
        3536                 :           {
        3537               0 :             entry->mNodeOffset = startOffset = rngStartOffset;
        3538               0 :             adjustStr = true;
        3539                 :           }
        3540                 :
        3541               0 :           if (entry->mNode == rngEndNode)
        3542                 :           {
        3543               0 :             endOffset = rngEndOffset;
        3544               0 :             adjustStr = true;
        3545                 :           }
        3546                 :
        3547               0 :           if (adjustStr)
        3548                 :           {
        3549               0 :             entry->mLength = endOffset - startOffset;
        3550               0 :             str = Substring(str, startOffset, entry->mLength);
        3551                 :           }
        3552                 :
        3553               0 :           offset += str.Length();
        3554                 :
        3555               0 :           if (aStr)
        3556                 :           {
        3557                 :             // Append the text node's string to the output string:
        3558                 :
        3559               0 :             if (!first)
        3560               0 :               *aStr = str;
        3561                 :             else
        3562               0 :               *aStr += str;
        3563                 :           }
        3564                 :         }
        3565                 :
        3566               0 :         prev = content;
        3567                 :
        3568               0 :         if (!first)
        3569               0 :           first = content;
        3570                 :       }
        3571                 :       else
        3572                 :         break;
        3573                 :
        3574                 :     }
        3575               0 :     else if (IsBlockNode(content))
        3576                 :       break;
        3577                 :
        3578               0 :     aIterator->Next();
        3579                 :
        3580               0 :     if (DidSkip(aIterator))
        3581                 :       break;
        3582                 :   }
        3583                 :
        3584               0 :   if (first)
        3585                 :   {
        3586                 :     // Always leave the iterator pointing at the first
        3587                 :     // text node of the current block!
        3588                 :
        3589               0 :     aIterator->PositionAt(first);
        3590                 :   }
        3591                 :   else
        3592                 :   {
        3593                 :     // If we never ran across a text node, the iterator
        3594                 :     // might have been pointing to something invalid to
        3595                 :     // begin with.
        3596                 :
        3597               0 :     *aIteratorStatus = nsTextServicesDocument::eIsDone;
        3598                 :   }
        3599                 :
        3600               0 :   return result;
        3601                 : }
        3602                 :
        3603                 : nsresult
        3604               0 : nsTextServicesDocument::RemoveInvalidOffsetEntries()
        3605                 : {
        3606                 :   OffsetEntry *entry;
        3607               0 :   PRInt32 i = 0;
        3608                 :
        3609               0 :   while (PRUint32(i) < mOffsetTable.Length())
        3610                 :   {
        3611               0 :     entry = mOffsetTable[i];
        3612                 :
        3613               0 :     if (!entry->mIsValid)
        3614                 :     {
        3615               0 :       mOffsetTable.RemoveElementAt(i);
        3616                 :
        3617               0 :       if (mSelStartIndex >= 0 && mSelStartIndex >= i)
        3618                 :       {
        3619                 :         // We are deleting an entry that comes before
        3620                 :         // mSelStartIndex, decrement mSelStartIndex so
        3621                 :         // that it points to the correct entry!
        3622                 :
        3623               0 :         NS_ASSERTION(i != mSelStartIndex, "Invalid selection index.");
        3624                 :
        3625               0 :         --mSelStartIndex;
        3626               0 :         --mSelEndIndex;
        3627                 :       }
        3628                 :     }
        3629                 :     else
        3630               0 :       i++;
        3631                 :   }
        3632                 :
        3633               0 :   return NS_OK;
        3634                 : }
        3635                 :
        3636                 : nsresult
        3637               0 : nsTextServicesDocument::ClearOffsetTable(nsTArray<OffsetEntry*> *aOffsetTable)
        3638                 : {
        3639                 :   PRUint32 i;
        3640                 :
        3641               0 :   for (i = 0; i < aOffsetTable->Length(); i++)
        3642                 :   {
        3643               0 :     delete aOffsetTable->ElementAt(i);
        3644                 :   }
        3645                 :
        3646               0 :   aOffsetTable->Clear();
        3647                 :
        3648               0 :   return NS_OK;
        3649                 : }
        3650                 :
        3651                 : nsresult
        3652               0 : nsTextServicesDocument::SplitOffsetEntry(PRInt32 aTableIndex, PRInt32 aNewEntryLength)
        3653                 : {
        3654               0 :   OffsetEntry *entry = mOffsetTable[aTableIndex];
        3655                 :
        3656               0 :   NS_ASSERTION((aNewEntryLength > 0), "aNewEntryLength <= 0");
        3657               0 :   NS_ASSERTION((aNewEntryLength < entry->mLength), "aNewEntryLength >= mLength");
        3658                 :
        3659               0 :   if (aNewEntryLength < 1 || aNewEntryLength >= entry->mLength)
        3660               0 :     return NS_ERROR_FAILURE;
        3661                 :
        3662               0 :   PRInt32 oldLength = entry->mLength - aNewEntryLength;
        3663                 :
        3664                 :   OffsetEntry *newEntry = new OffsetEntry(entry->mNode,
        3665                 :                                           entry->mStrOffset + oldLength,
        3666               0 :                                           aNewEntryLength);
        3667                 :
        3668               0 :   if (!mOffsetTable.InsertElementAt(aTableIndex + 1, newEntry))
        3669                 :   {
        3670               0 :     delete newEntry;
        3671               0 :     return NS_ERROR_FAILURE;
        3672                 :   }
        3673                 :
        3674                 :    // Adjust entry fields:
        3675                 :
        3676               0 :    entry->mLength        = oldLength;
        3677               0 :    newEntry->mNodeOffset = entry->mNodeOffset + oldLength;
        3678                 :
        3679               0 :   return NS_OK;
        3680                 : }
        3681                 :
        3682                 : nsresult
        3683               0 : nsTextServicesDocument::NodeHasOffsetEntry(nsTArray<OffsetEntry*> *aOffsetTable, nsIDOMNode *aNode, bool *aHasEntry, PRInt32 *aEntryIndex)
        3684                 : {
        3685                 :   OffsetEntry *entry;
        3686                 :   PRUint32 i;
        3687                 :
        3688               0 :   NS_ENSURE_TRUE(aNode && aHasEntry && aEntryIndex, NS_ERROR_NULL_POINTER);
        3689                 :
        3690               0 :   for (i = 0; i < aOffsetTable->Length(); i++)
        3691                 :   {
        3692               0 :     entry = (*aOffsetTable)[i];
        3693                 :
        3694               0 :     NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
        3695                 :
        3696               0 :     if (entry->mNode == aNode)
        3697                 :     {
        3698               0 :       *aHasEntry   = true;
        3699               0 :       *aEntryIndex = i;
        3700                 :
        3701               0 :       return NS_OK;
        3702                 :     }
        3703                 :   }
        3704                 :
        3705               0 :   *aHasEntry   = false;
        3706               0 :   *aEntryIndex = -1;
        3707                 :
        3708               0 :   return NS_OK;
        3709                 : }
        3710                 :
        3711                 : // Spellchecker code has this. See bug 211343
        3712                 : #define IS_NBSP_CHAR(c) (((unsigned char)0xa0)==(c))
        3713                 :
        3714                 : nsresult
        3715               0 : nsTextServicesDocument::FindWordBounds(nsTArray<OffsetEntry*> *aOffsetTable,
        3716                 :                                        nsString *aBlockStr,
        3717                 :                                        nsIDOMNode *aNode,
        3718                 :                                        PRInt32 aNodeOffset,
        3719                 :                                        nsIDOMNode **aWordStartNode,
        3720                 :                                        PRInt32 *aWordStartOffset,
        3721                 :                                        nsIDOMNode **aWordEndNode,
        3722                 :                                        PRInt32 *aWordEndOffset)
        3723                 : {
        3724                 :   // Initialize return values.
        3725                 :
        3726               0 :   if (aWordStartNode)
        3727               0 :     *aWordStartNode = nsnull;
        3728               0 :   if (aWordStartOffset)
        3729               0 :     *aWordStartOffset = 0;
        3730               0 :   if (aWordEndNode)
        3731               0 :     *aWordEndNode = nsnull;
        3732               0 :   if (aWordEndOffset)
        3733               0 :     *aWordEndOffset = 0;
        3734                 :
        3735               0 :   PRInt32 entryIndex = 0;
        3736               0 :   bool hasEntry = false;
        3737                 :
        3738                 :   // It's assumed that aNode is a text node. The first thing
        3739                 :   // we do is get its index in the offset table so we can
        3740                 :   // calculate the dom point's string offset.
        3741                 :
        3742               0 :   nsresult result = NodeHasOffsetEntry(aOffsetTable, aNode, &hasEntry, &entryIndex);
        3743               0 :   NS_ENSURE_SUCCESS(result, result);
        3744               0 :   NS_ENSURE_TRUE(hasEntry, NS_ERROR_FAILURE);
        3745                 :
        3746                 :   // Next we map aNodeOffset into a string offset.
        3747                 :
        3748               0 :   OffsetEntry *entry = (*aOffsetTable)[entryIndex];
        3749               0 :   PRUint32 strOffset = entry->mStrOffset + aNodeOffset - entry->mNodeOffset;
        3750                 :
        3751                 :   // Now we use the word breaker to find the beginning and end
        3752                 :   // of the word from our calculated string offset.
        3753                 :
        3754               0 :   const PRUnichar *str = aBlockStr->get();
        3755               0 :   PRUint32 strLen = aBlockStr->Length();
        3756                 :
        3757                 :   nsIWordBreaker *aWordBreaker;
        3758                 :
        3759               0 :   result = CallGetService(NS_WBRK_CONTRACTID, &aWordBreaker);
        3760               0 :   NS_ENSURE_SUCCESS(result, result);
        3761                 :
        3762               0 :   nsWordRange res = aWordBreaker->FindWord(str, strLen, strOffset);
        3763               0 :   NS_IF_RELEASE(aWordBreaker);
        3764               0 :   if(res.mBegin > strLen)
        3765                 :   {
        3766               0 :     if(!str)
        3767               0 :       return NS_ERROR_NULL_POINTER;
        3768                 :     else
        3769               0 :       return NS_ERROR_ILLEGAL_VALUE;
        3770                 :   }
        3771                 :
        3772                 :   // Strip out the NBSPs at the ends
        3773               0 :   while ((res.mBegin <= res.mEnd) && (IS_NBSP_CHAR(str[res.mBegin])))
        3774               0 :     res.mBegin++;
        3775               0 :   if (str[res.mEnd] == (unsigned char)0x20)
        3776                 :   {
        3777               0 :     PRUint32 realEndWord = res.mEnd - 1;
        3778               0 :     while ((realEndWord > res.mBegin) && (IS_NBSP_CHAR(str[realEndWord])))
        3779               0 :       realEndWord--;
        3780               0 :     if (realEndWord < res.mEnd - 1)
        3781               0 :       res.mEnd = realEndWord + 1;
        3782                 :   }
        3783                 :
        3784                 :   // Now that we have the string offsets for the beginning
        3785                 :   // and end of the word, run through the offset table and
        3786                 :   // convert them back into dom points.
        3787                 :
        3788               0 :   PRInt32 i, lastIndex = aOffsetTable->Length() - 1;
        3789                 :
        3790               0 :   for (i=0; i <= lastIndex; i++)
        3791                 :   {
        3792               0 :     entry = (*aOffsetTable)[i];
        3793                 :
        3794               0 :     PRInt32 strEndOffset = entry->mStrOffset + entry->mLength;
        3795                 :
        3796                 :     // Check to see if res.mBegin is within the range covered
        3797                 :     // by this entry. Note that if res.mBegin is after the last
        3798                 :     // character covered by this entry, we will use the next
        3799                 :     // entry if there is one.
        3800                 :
        3801               0 :     if (PRUint32(entry->mStrOffset) <= res.mBegin &&
        3802                 :         (res.mBegin < PRUint32(strEndOffset) ||
        3803                 :         (res.mBegin == PRUint32(strEndOffset) && i == lastIndex)))
        3804                 :     {
        3805               0 :       if (aWordStartNode)
        3806                 :       {
        3807               0 :         *aWordStartNode = entry->mNode;
        3808               0 :         NS_IF_ADDREF(*aWordStartNode);
        3809                 :       }
        3810                 :
        3811               0 :       if (aWordStartOffset)
        3812               0 :         *aWordStartOffset = entry->mNodeOffset + res.mBegin - entry->mStrOffset;
        3813                 :
        3814               0 :       if (!aWordEndNode && !aWordEndOffset)
        3815                 :       {
        3816                 :         // We've found our start entry, but if we're not looking
        3817                 :         // for end entries, we're done.
        3818                 :
        3819               0 :         break;
        3820                 :       }
        3821                 :     }
        3822                 :
        3823                 :     // Check to see if res.mEnd is within the range covered
        3824                 :     // by this entry.
        3825                 :
        3826               0 :     if (PRUint32(entry->mStrOffset) <= res.mEnd && res.mEnd <= PRUint32(strEndOffset))
        3827                 :     {
        3828               0 :       if (res.mBegin == res.mEnd && res.mEnd == PRUint32(strEndOffset) && i != lastIndex)
        3829                 :       {
        3830                 :         // Wait for the next round so that we use the same entry
        3831                 :         // we did for aWordStartNode.
        3832                 :
        3833               0 :         continue;
        3834                 :       }
        3835                 :
        3836               0 :       if (aWordEndNode)
        3837                 :       {
        3838               0 :         *aWordEndNode = entry->mNode;
        3839               0 :         NS_IF_ADDREF(*aWordEndNode);
        3840                 :       }
        3841                 :
        3842               0 :       if (aWordEndOffset)
        3843               0 :         *aWordEndOffset = entry->mNodeOffset + res.mEnd - entry->mStrOffset;
        3844                 :
        3845               0 :       break;
        3846                 :     }
        3847                 :   }
        3848                 :
        3849                 :
        3850               0 :   return NS_OK;
        3851                 : }
        3852                 :
        3853                 : #ifdef DEBUG_kin
        3854                 : void
        3855                 : nsTextServicesDocument::PrintOffsetTable()
        3856                 : {
        3857                 :   OffsetEntry *entry;
        3858                 :   PRUint32 i;
        3859                 :
        3860                 :   for (i = 0; i < mOffsetTable.Length(); i++)
        3861                 :   {
        3862                 :     entry = mOffsetTable[i];
        3863                 :     printf("ENTRY %4d: %p  %c  %c  %4d  %4d  %4d\n",
        3864                 :            i, entry->mNode,  entry->mIsValid ? 'V' : 'N',
        3865                 :            entry->mIsInsertedText ? 'I' : 'B',
        3866                 :            entry->mNodeOffset, entry->mStrOffset, entry->mLength);
        3867                 :   }
        3868                 :
        3869                 :   fflush(stdout);
        3870                 : }
        3871                 :
        3872                 : void
        3873                 : nsTextServicesDocument::PrintContentNode(nsIContent *aContent)
        3874                 : {
        3875                 :   nsString tmpStr, str;
        3876                 :
        3877                 :   aContent->Tag()->ToString(tmpStr);
        3878                 :   printf("%s", NS_LossyConvertUTF16toASCII(tmpStr).get());
        3879                 :
        3880                 :   if (nsIDOMNode::TEXT_NODE == aContent->NodeType())
        3881                 :   {
        3882                 :     aContent->AppendTextTo(str);
        3883                 :     printf(":  \"%s\"", NS_LossyConvertUTF16toASCII(str).get());
        3884                 :   }
        3885                 :
        3886                 :   printf("\n");
        3887                 :   fflush(stdout);
        3888                 : }
        3889                 : #endif
        3890                 :
        3891                 : NS_IMETHODIMP
        3892               0 : nsTextServicesDocument::WillInsertNode(nsIDOMNode *aNode,
        3893                 :                               nsIDOMNode *aParent,
        3894                 :                               PRInt32     aPosition)
        3895                 : {
        3896               0 :   return NS_OK;
        3897                 : }
        3898                 :
        3899                 : NS_IMETHODIMP
        3900               0 : nsTextServicesDocument::WillDeleteNode(nsIDOMNode *aChild)
        3901                 : {
        3902               0 :   return NS_OK;
        3903                 : }
        3904                 :
        3905                 : NS_IMETHODIMP
        3906               0 : nsTextServicesDocument::WillSplitNode(nsIDOMNode *aExistingRightNode,
        3907                 :                              PRInt32     aOffset)
        3908                 : {
        3909               0 :   return NS_OK;
        3910                 : }
        3911                 :
        3912                 : NS_IMETHODIMP
        3913               0 : nsTextServicesDocument::WillJoinNodes(nsIDOMNode  *aLeftNode,
        3914                 :                              nsIDOMNode  *aRightNode,
        3915                 :                              nsIDOMNode  *aParent)
        3916                 : {
        3917               0 :   return NS_OK;
        3918                 : }
        3919                 :
        3920                 :
        3921                 : // -------------------------------
        3922                 : // stubs for unused listen methods
        3923                 : // -------------------------------
        3924                 :
        3925                 : NS_IMETHODIMP
        3926               0 : nsTextServicesDocument::WillCreateNode(const nsAString& aTag, nsIDOMNode *aParent, PRInt32 aPosition)
        3927                 : {
        3928               0 :   return NS_OK;
        3929                 : }
        3930                 :
        3931                 : NS_IMETHODIMP
        3932               0 : nsTextServicesDocument::DidCreateNode(const nsAString& aTag, nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aPosition, nsresult aResult)
        3933                 : {
        3934               0 :   return NS_OK;
        3935                 : }
        3936                 :
        3937                 : NS_IMETHODIMP
        3938               0 : nsTextServicesDocument::WillInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsAString &aString)
        3939                 : {
        3940               0 :   return NS_OK;
        3941                 : }
        3942                 :
        3943                 : NS_IMETHODIMP
        3944               0 : nsTextServicesDocument::DidInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsAString &aString, nsresult aResult)
        3945                 : {
        3946               0 :   return NS_OK;
        3947                 : }
        3948                 :
        3949                 : NS_IMETHODIMP
        3950               0 : nsTextServicesDocument::WillDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
        3951                 : {
        3952               0 :   return NS_OK;
        3953                 : }
        3954                 :
        3955                 : NS_IMETHODIMP
        3956               0 : nsTextServicesDocument::DidDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength, nsresult aResult)
        3957                 : {
        3958               0 :   return NS_OK;
        3959                 : }
        3960                 :
        3961                 : NS_IMETHODIMP
        3962               0 : nsTextServicesDocument::WillDeleteSelection(nsISelection *aSelection)
        3963                 : {
        3964               0 :   return NS_OK;
        3965                 : }
        3966                 :
        3967                 : NS_IMETHODIMP
        3968               0 : nsTextServicesDocument::DidDeleteSelection(nsISelection *aSelection)
        3969                 : {
        3970               0 :   return NS_OK;
        3971            4392 : }
        3972                 :

Generated by: LCOV version 1.7