LCOV - code coverage report
Current view: top level - extensions/spellcheck/src - mozSpellChecker.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 45 292 15.4 %
Date: 2017-07-14 16:53:18 Functions: 7 25 28.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13