LCOV - code coverage report
Current view: directory - extensions/spellcheck/src - mozSpellChecker.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 256 2 0.8 %
Date: 2012-06-02 Functions: 27 2 7.4 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Mozilla Spellchecker Component.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is David Einstein.
      17                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      18                 :  * the Initial Developer. All Rights Reserved.
      19                 :  *
      20                 :  * Contributor(s): David Einstein Deinst@world.std.com
      21                 :  *   Jesper Kristensen <mail@jesperkristensen.dk>
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : 
      38                 : #include "mozSpellChecker.h"
      39                 : #include "nsIServiceManager.h"
      40                 : #include "mozISpellI18NManager.h"
      41                 : #include "nsIStringEnumerator.h"
      42                 : #include "nsICategoryManager.h"
      43                 : #include "nsISupportsPrimitives.h"
      44                 : 
      45                 : #define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1"
      46                 : 
      47               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(mozSpellChecker)
      48               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(mozSpellChecker)
      49                 : 
      50               0 : NS_INTERFACE_MAP_BEGIN(mozSpellChecker)
      51               0 :   NS_INTERFACE_MAP_ENTRY(nsISpellChecker)
      52               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpellChecker)
      53               0 :   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozSpellChecker)
      54               0 : NS_INTERFACE_MAP_END
      55                 : 
      56            1464 : NS_IMPL_CYCLE_COLLECTION_3(mozSpellChecker,
      57                 :                            mConverter,
      58                 :                            mTsDoc,
      59                 :                            mPersonalDictionary)
      60                 : 
      61               0 : mozSpellChecker::mozSpellChecker()
      62                 : {
      63               0 : }
      64                 : 
      65               0 : mozSpellChecker::~mozSpellChecker()
      66                 : {
      67               0 :   if(mPersonalDictionary){
      68                 :     //    mPersonalDictionary->Save();
      69               0 :     mPersonalDictionary->EndSession();
      70                 :   }
      71               0 :   mSpellCheckingEngine = nsnull;
      72               0 :   mPersonalDictionary = nsnull;
      73               0 : }
      74                 : 
      75                 : nsresult 
      76               0 : mozSpellChecker::Init()
      77                 : {
      78               0 :   mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
      79                 :   
      80               0 :   mSpellCheckingEngine = nsnull;
      81                 : 
      82               0 :   return NS_OK;
      83                 : } 
      84                 : 
      85                 : NS_IMETHODIMP 
      86               0 : mozSpellChecker::SetDocument(nsITextServicesDocument *aDoc, bool aFromStartofDoc)
      87                 : {
      88               0 :   mTsDoc = aDoc;
      89               0 :   mFromStart = aFromStartofDoc;
      90               0 :   return NS_OK;
      91                 : }
      92                 : 
      93                 : 
      94                 : NS_IMETHODIMP 
      95               0 : mozSpellChecker::NextMisspelledWord(nsAString &aWord, nsTArray<nsString> *aSuggestions)
      96                 : {
      97               0 :   if(!aSuggestions||!mConverter)
      98               0 :     return NS_ERROR_NULL_POINTER;
      99                 : 
     100                 :   PRInt32 selOffset;
     101                 :   PRInt32 begin,end;
     102                 :   nsresult result;
     103               0 :   result = SetupDoc(&selOffset);
     104                 :   bool isMisspelled,done;
     105               0 :   if (NS_FAILED(result))
     106               0 :     return result;
     107                 : 
     108               0 :   while( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done )
     109                 :     {
     110               0 :       nsString str;
     111               0 :       result = mTsDoc->GetCurrentTextBlock(&str);
     112                 :   
     113               0 :       if (NS_FAILED(result))
     114               0 :         return result;
     115               0 :       do{
     116               0 :         result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end);
     117               0 :         if(NS_SUCCEEDED(result)&&(begin != -1)){
     118               0 :           const nsAString &currWord = Substring(str, begin, end - begin);
     119               0 :           result = CheckWord(currWord, &isMisspelled, aSuggestions);
     120               0 :           if(isMisspelled){
     121               0 :             aWord = currWord;
     122               0 :             mTsDoc->SetSelection(begin, end-begin);
     123                 :             // After ScrollSelectionIntoView(), the pending notifications might
     124                 :             // be flushed and PresShell/PresContext/Frames may be dead.
     125                 :             // See bug 418470.
     126               0 :             mTsDoc->ScrollSelectionIntoView();
     127               0 :             return NS_OK;
     128                 :           }
     129                 :         }
     130               0 :         selOffset = end;
     131                 :       }while(end != -1);
     132               0 :       mTsDoc->NextBlock();
     133               0 :       selOffset=0;
     134                 :     }
     135               0 :   return NS_OK;
     136                 : }
     137                 : 
     138                 : NS_IMETHODIMP 
     139               0 : mozSpellChecker::CheckWord(const nsAString &aWord, bool *aIsMisspelled, nsTArray<nsString> *aSuggestions)
     140                 : {
     141                 :   nsresult result;
     142                 :   bool correct;
     143               0 :   if(!mSpellCheckingEngine)
     144               0 :     return NS_ERROR_NULL_POINTER;
     145                 : 
     146               0 :   *aIsMisspelled = false;
     147               0 :   result = mSpellCheckingEngine->Check(PromiseFlatString(aWord).get(), &correct);
     148               0 :   NS_ENSURE_SUCCESS(result, result);
     149               0 :   if(!correct){
     150               0 :     if(aSuggestions){
     151                 :       PRUint32 count,i;
     152                 :       PRUnichar **words;
     153                 :       
     154               0 :       result = mSpellCheckingEngine->Suggest(PromiseFlatString(aWord).get(), &words, &count);
     155               0 :       NS_ENSURE_SUCCESS(result, result); 
     156               0 :       for(i=0;i<count;i++){
     157               0 :         aSuggestions->AppendElement(nsDependentString(words[i]));
     158                 :       }
     159                 :       
     160               0 :       if (count)
     161               0 :         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
     162                 :     }
     163               0 :     *aIsMisspelled = true;
     164                 :   }
     165               0 :   return NS_OK;
     166                 : }
     167                 : 
     168                 : NS_IMETHODIMP 
     169               0 : mozSpellChecker::Replace(const nsAString &aOldWord, const nsAString &aNewWord, bool aAllOccurrences)
     170                 : {
     171               0 :   if(!mConverter)
     172               0 :     return NS_ERROR_NULL_POINTER;
     173                 : 
     174               0 :   nsAutoString newWord(aNewWord); // sigh
     175                 : 
     176               0 :   if(aAllOccurrences){
     177                 :     PRInt32 selOffset;
     178                 :     PRInt32 startBlock,currentBlock,currOffset;
     179                 :     PRInt32 begin,end;
     180                 :     bool done;
     181                 :     nsresult result;
     182               0 :     nsAutoString str;
     183                 : 
     184                 :     // find out where we are
     185               0 :     result = SetupDoc(&selOffset);
     186               0 :     if(NS_FAILED(result))
     187               0 :       return result;
     188               0 :     result = GetCurrentBlockIndex(mTsDoc,&startBlock);
     189               0 :     if(NS_FAILED(result))
     190               0 :       return result;
     191                 : 
     192                 :     //start at the beginning
     193               0 :     result = mTsDoc->FirstBlock();
     194               0 :     currOffset=0;
     195               0 :     currentBlock = 0;
     196               0 :     while( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done )
     197                 :       {
     198               0 :         result = mTsDoc->GetCurrentTextBlock(&str);
     199               0 :         do{
     200               0 :           result = mConverter->FindNextWord(str.get(),str.Length(),currOffset,&begin,&end);
     201               0 :           if(NS_SUCCEEDED(result)&&(begin != -1)){
     202               0 :             if (aOldWord.Equals(Substring(str, begin, end-begin))) {
     203                 :               // if we are before the current selection point but in the same block
     204                 :               // move the selection point forwards
     205               0 :               if((currentBlock == startBlock)&&(begin < selOffset)){
     206                 :                 selOffset +=
     207               0 :                   PRInt32(aNewWord.Length()) - PRInt32(aOldWord.Length());
     208               0 :                 if(selOffset < begin) selOffset=begin;
     209                 :               }
     210               0 :               mTsDoc->SetSelection(begin, end-begin);
     211               0 :               mTsDoc->InsertText(&newWord);
     212               0 :               mTsDoc->GetCurrentTextBlock(&str);
     213               0 :               end += (aNewWord.Length() - aOldWord.Length());  // recursion was cute in GEB, not here.
     214                 :             }
     215                 :           }
     216               0 :           currOffset = end;
     217                 :         }while(currOffset != -1);
     218               0 :         mTsDoc->NextBlock();
     219               0 :         currentBlock++;
     220               0 :         currOffset=0;          
     221                 :       }
     222                 : 
     223                 :     // We are done replacing.  Put the selection point back where we found  it (or equivalent);
     224               0 :     result = mTsDoc->FirstBlock();
     225               0 :     currentBlock = 0;
     226               0 :     while(( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done ) &&(currentBlock < startBlock)){
     227               0 :       mTsDoc->NextBlock();
     228                 :     }
     229                 : 
     230                 : //After we have moved to the block where the first occurrence of replace was done, put the 
     231                 : //selection to the next word following it. In case there is no word following it i.e if it happens
     232                 : //to be the last word in that block, then move to the next block and put the selection to the 
     233                 : //first word in that block, otherwise when the Setupdoc() is called, it queries the LastSelectedBlock()
     234                 : //and the selection offset of the last occurrence of the replaced word is taken instead of the first 
     235                 : //occurrence and things get messed up as reported in the bug 244969
     236                 : 
     237               0 :     if( NS_SUCCEEDED(mTsDoc->IsDone(&done)) && !done ){
     238               0 :       nsString str;                                
     239               0 :       result = mTsDoc->GetCurrentTextBlock(&str);  
     240               0 :       result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end);
     241               0 :             if(end == -1)
     242                 :              {
     243               0 :                 mTsDoc->NextBlock();
     244               0 :                 selOffset=0;
     245               0 :                 result = mTsDoc->GetCurrentTextBlock(&str); 
     246               0 :                 result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end);
     247               0 :                 mTsDoc->SetSelection(begin, 0);
     248                 :              }
     249                 :          else
     250               0 :                 mTsDoc->SetSelection(begin, 0);
     251                 :     }
     252                 :  }
     253                 :   else{
     254               0 :     mTsDoc->InsertText(&newWord);
     255                 :   }
     256               0 :   return NS_OK;
     257                 : }
     258                 : 
     259                 : NS_IMETHODIMP 
     260               0 : mozSpellChecker::IgnoreAll(const nsAString &aWord)
     261                 : {
     262               0 :   if(mPersonalDictionary){
     263               0 :     mPersonalDictionary->IgnoreWord(PromiseFlatString(aWord).get());
     264                 :   }
     265               0 :   return NS_OK;
     266                 : }
     267                 : 
     268                 : NS_IMETHODIMP 
     269               0 : mozSpellChecker::AddWordToPersonalDictionary(const nsAString &aWord)
     270                 : {
     271                 :   nsresult res;
     272               0 :   PRUnichar empty=0;
     273               0 :   if (!mPersonalDictionary)
     274               0 :     return NS_ERROR_NULL_POINTER;
     275               0 :   res = mPersonalDictionary->AddWord(PromiseFlatString(aWord).get(),&empty);
     276               0 :   return res;
     277                 : }
     278                 : 
     279                 : NS_IMETHODIMP 
     280               0 : mozSpellChecker::RemoveWordFromPersonalDictionary(const nsAString &aWord)
     281                 : {
     282                 :   nsresult res;
     283               0 :   PRUnichar empty=0;
     284               0 :   if (!mPersonalDictionary)
     285               0 :     return NS_ERROR_NULL_POINTER;
     286               0 :   res = mPersonalDictionary->RemoveWord(PromiseFlatString(aWord).get(),&empty);
     287               0 :   return res;
     288                 : }
     289                 : 
     290                 : NS_IMETHODIMP 
     291               0 : mozSpellChecker::GetPersonalDictionary(nsTArray<nsString> *aWordList)
     292                 : {
     293               0 :   if(!aWordList || !mPersonalDictionary)
     294               0 :     return NS_ERROR_NULL_POINTER;
     295                 : 
     296               0 :   nsCOMPtr<nsIStringEnumerator> words;
     297               0 :   mPersonalDictionary->GetWordList(getter_AddRefs(words));
     298                 :   
     299                 :   bool hasMore;
     300               0 :   nsAutoString word;
     301               0 :   while (NS_SUCCEEDED(words->HasMore(&hasMore)) && hasMore) {
     302               0 :     words->GetNext(word);
     303               0 :     aWordList->AppendElement(word);
     304                 :   }
     305               0 :   return NS_OK;
     306                 : }
     307                 : 
     308                 : NS_IMETHODIMP 
     309               0 : mozSpellChecker::GetDictionaryList(nsTArray<nsString> *aDictionaryList)
     310                 : {
     311                 :   nsresult rv;
     312                 : 
     313                 :   // For catching duplicates
     314               0 :   nsClassHashtable<nsStringHashKey, nsCString> dictionaries;
     315               0 :   dictionaries.Init();
     316                 : 
     317               0 :   nsCOMArray<mozISpellCheckingEngine> spellCheckingEngines;
     318               0 :   rv = GetEngineList(&spellCheckingEngines);
     319               0 :   NS_ENSURE_SUCCESS(rv, rv);
     320                 : 
     321               0 :   for (PRUint32 i = 0; i < spellCheckingEngines.Count(); i++) {
     322               0 :     nsCOMPtr<mozISpellCheckingEngine> engine = spellCheckingEngines[i];
     323                 : 
     324               0 :     PRUint32 count = 0;
     325               0 :     PRUnichar **words = NULL;
     326               0 :     engine->GetDictionaryList(&words, &count);
     327               0 :     for (PRUint32 k = 0; k < count; k++) {
     328               0 :       nsAutoString dictName;
     329                 : 
     330               0 :       dictName.Assign(words[k]);
     331                 : 
     332                 :       // Skip duplicate dictionaries. Only take the first one
     333                 :       // for each name.
     334               0 :       if (dictionaries.Get(dictName, NULL))
     335               0 :         continue;
     336                 : 
     337               0 :       dictionaries.Put(dictName, NULL);
     338                 : 
     339               0 :       if (!aDictionaryList->AppendElement(dictName)) {
     340               0 :         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
     341               0 :         return NS_ERROR_OUT_OF_MEMORY;
     342                 :       }
     343                 :     }
     344                 : 
     345               0 :     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
     346                 :   }
     347                 : 
     348               0 :   return NS_OK;
     349                 : }
     350                 : 
     351                 : NS_IMETHODIMP 
     352               0 : mozSpellChecker::GetCurrentDictionary(nsAString &aDictionary)
     353                 : {
     354               0 :   if (!mSpellCheckingEngine) {
     355               0 :     aDictionary.AssignLiteral("");
     356               0 :     return NS_OK;
     357                 :   }
     358                 : 
     359               0 :   nsXPIDLString dictname;
     360               0 :   mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
     361               0 :   aDictionary = dictname;
     362               0 :   return NS_OK;
     363                 : }
     364                 : 
     365                 : NS_IMETHODIMP 
     366               0 : mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
     367                 : {
     368               0 :   mSpellCheckingEngine = nsnull;
     369                 : 
     370               0 :   if (aDictionary.IsEmpty()) {
     371               0 :     return NS_OK;
     372                 :   }
     373                 : 
     374                 :   nsresult rv;
     375               0 :   nsCOMArray<mozISpellCheckingEngine> spellCheckingEngines;
     376               0 :   rv = GetEngineList(&spellCheckingEngines);
     377               0 :   NS_ENSURE_SUCCESS(rv, rv);
     378                 : 
     379               0 :   for (PRUint32 i = 0; i < spellCheckingEngines.Count(); i++) {
     380                 :     // We must set mSpellCheckingEngine before we call SetDictionary, since
     381                 :     // SetDictionary calls back to this spell checker to check if the
     382                 :     // dictionary was set
     383               0 :     mSpellCheckingEngine = spellCheckingEngines[i];
     384                 : 
     385               0 :     rv = mSpellCheckingEngine->SetDictionary(PromiseFlatString(aDictionary).get());
     386                 : 
     387               0 :     if (NS_SUCCEEDED(rv)) {
     388               0 :       nsCOMPtr<mozIPersonalDictionary> personalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
     389               0 :       mSpellCheckingEngine->SetPersonalDictionary(personalDictionary.get());
     390                 : 
     391               0 :       nsXPIDLString language;
     392               0 :       nsCOMPtr<mozISpellI18NManager> serv(do_GetService("@mozilla.org/spellchecker/i18nmanager;1", &rv));
     393               0 :       NS_ENSURE_SUCCESS(rv, rv);
     394               0 :       return serv->GetUtil(language.get(),getter_AddRefs(mConverter));
     395                 :     }
     396                 :   }
     397                 : 
     398               0 :   mSpellCheckingEngine = NULL;
     399                 :   
     400                 :   // We could not find any engine with the requested dictionary
     401               0 :   return NS_ERROR_NOT_AVAILABLE;
     402                 : }
     403                 : 
     404                 : NS_IMETHODIMP 
     405               0 : mozSpellChecker::CheckCurrentDictionary()
     406                 : {
     407                 :   // If the current dictionary has been uninstalled, we need to stop using it.
     408                 :   // This happens when there is a current engine, but that engine has no
     409                 :   // current dictionary.
     410                 : 
     411               0 :   if (!mSpellCheckingEngine) {
     412                 :     // We didn't have a current dictionary
     413               0 :     return NS_OK;
     414                 :   }
     415                 : 
     416               0 :   nsXPIDLString dictname;
     417               0 :   mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
     418                 : 
     419               0 :   if (!dictname.IsEmpty()) {
     420                 :     // We still have a current dictionary
     421               0 :     return NS_OK;
     422                 :   }
     423                 : 
     424                 :   // We had a current dictionary, but it has gone, so we cannot use it anymore.
     425               0 :   mSpellCheckingEngine = nsnull;
     426               0 :   return NS_OK;
     427                 : }
     428                 : 
     429                 : nsresult
     430               0 : mozSpellChecker::SetupDoc(PRInt32 *outBlockOffset)
     431                 : {
     432                 :   nsresult  rv;
     433                 : 
     434                 :   nsITextServicesDocument::TSDBlockSelectionStatus blockStatus;
     435                 :   PRInt32 selOffset;
     436                 :   PRInt32 selLength;
     437               0 :   *outBlockOffset = 0;
     438                 : 
     439               0 :   if (!mFromStart) 
     440                 :   {
     441               0 :     rv = mTsDoc->LastSelectedBlock(&blockStatus, &selOffset, &selLength);
     442               0 :     if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound))
     443                 :     {
     444               0 :       switch (blockStatus)
     445                 :       {
     446                 :         case nsITextServicesDocument::eBlockOutside:  // No TB in S, but found one before/after S.
     447                 :         case nsITextServicesDocument::eBlockPartial:  // S begins or ends in TB but extends outside of TB.
     448                 :           // the TS doc points to the block we want.
     449               0 :           *outBlockOffset = selOffset + selLength;
     450               0 :           break;
     451                 :                     
     452                 :         case nsITextServicesDocument::eBlockInside:  // S extends beyond the start and end of TB.
     453                 :           // we want the block after this one.
     454               0 :           rv = mTsDoc->NextBlock();
     455               0 :           *outBlockOffset = 0;
     456               0 :           break;
     457                 :                 
     458                 :         case nsITextServicesDocument::eBlockContains: // TB contains entire S.
     459               0 :           *outBlockOffset = selOffset + selLength;
     460               0 :           break;
     461                 :         
     462                 :         case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S).
     463                 :         default:
     464               0 :           NS_NOTREACHED("Shouldn't ever get this status");
     465                 :       }
     466                 :     }
     467                 :     else  //failed to get last sel block. Just start at beginning
     468                 :     {
     469               0 :       rv = mTsDoc->FirstBlock();
     470               0 :       *outBlockOffset = 0;
     471                 :     }
     472                 :   
     473                 :   }
     474                 :   else // we want the first block
     475                 :   {
     476               0 :     rv = mTsDoc->FirstBlock();
     477               0 :     mFromStart = false;
     478                 :   }
     479               0 :   return rv;
     480                 : }
     481                 : 
     482                 : 
     483                 : // utility method to discover which block we're in. The TSDoc interface doesn't give
     484                 : // us this, because it can't assume a read-only document.
     485                 : // shamelessly stolen from nsTextServicesDocument
     486                 : nsresult
     487               0 : mozSpellChecker::GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *outBlockIndex)
     488                 : {
     489               0 :   PRInt32  blockIndex = 0;
     490               0 :   bool     isDone = false;
     491               0 :   nsresult result = NS_OK;
     492                 : 
     493               0 :   do
     494                 :   {
     495               0 :     aDoc->PrevBlock();
     496                 : 
     497               0 :     result = aDoc->IsDone(&isDone);
     498                 : 
     499               0 :     if (!isDone)
     500               0 :       blockIndex ++;
     501                 : 
     502               0 :   } while (NS_SUCCEEDED(result) && !isDone);
     503                 :   
     504               0 :   *outBlockIndex = blockIndex;
     505                 : 
     506               0 :   return result;
     507                 : }
     508                 : 
     509                 : nsresult
     510               0 : mozSpellChecker::GetEngineList(nsCOMArray<mozISpellCheckingEngine>* aSpellCheckingEngines)
     511                 : {
     512                 :   nsresult rv;
     513                 :   bool hasMoreEngines;
     514                 : 
     515               0 :   nsCOMPtr<nsICategoryManager> catMgr = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
     516               0 :   if (!catMgr)
     517               0 :     return NS_ERROR_NULL_POINTER;
     518                 : 
     519               0 :   nsCOMPtr<nsISimpleEnumerator> catEntries;
     520                 : 
     521                 :   // Get contract IDs of registrated external spell-check engines and
     522                 :   // append one of HunSpell at the end.
     523               0 :   rv = catMgr->EnumerateCategory("spell-check-engine", getter_AddRefs(catEntries));
     524               0 :   if (NS_FAILED(rv))
     525               0 :     return rv;
     526                 : 
     527               0 :   while (catEntries->HasMoreElements(&hasMoreEngines), hasMoreEngines){
     528               0 :     nsCOMPtr<nsISupports> elem;
     529               0 :     rv = catEntries->GetNext(getter_AddRefs(elem));
     530                 : 
     531               0 :     nsCOMPtr<nsISupportsCString> entry = do_QueryInterface(elem, &rv);
     532               0 :     if (NS_FAILED(rv))
     533               0 :       return rv;
     534                 : 
     535               0 :     nsCString contractId;
     536               0 :     rv = entry->GetData(contractId);
     537               0 :     if (NS_FAILED(rv))
     538               0 :       return rv;
     539                 : 
     540                 :     // Try to load spellchecker engine. Ignore errors silently
     541                 :     // except for the last one (HunSpell).
     542                 :     nsCOMPtr<mozISpellCheckingEngine> engine =
     543               0 :       do_GetService(contractId.get(), &rv);
     544               0 :     if (NS_SUCCEEDED(rv)) {
     545               0 :       aSpellCheckingEngines->AppendObject(engine);
     546                 :     }
     547                 :   }
     548                 : 
     549                 :   // Try to load HunSpell spellchecker engine.
     550                 :   nsCOMPtr<mozISpellCheckingEngine> engine =
     551               0 :     do_GetService(DEFAULT_SPELL_CHECKER, &rv);
     552               0 :   if (NS_FAILED(rv)) {
     553                 :     // Fail if not succeeded to load HunSpell. Ignore errors
     554                 :     // for external spellcheck engines.
     555               0 :     return rv;
     556                 :   }
     557               0 :   aSpellCheckingEngines->AppendObject(engine);
     558                 : 
     559               0 :   return NS_OK;
     560            4392 : }

Generated by: LCOV version 1.7